From f395bf0491de31ce523f247fd8624c15687eaa57 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Thu, 4 Jul 2013 21:13:33 +0900 Subject: [PATCH 001/191] avoid '/*' in a comment --- lib/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/netdev.c b/lib/netdev.c index deccf950..a2e0841f 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -34,7 +34,7 @@ * * The modification includes code from libpcap; the copyright notice for that * code is - /* + * * pcap-linux.c: Packet capture interface to the Linux kernel * * Copyright (c) 2000 Torsten Landschoff From e4fffe30b8cca50c2736bc2d5fa58c235a308c5d Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Thu, 4 Jul 2013 21:14:17 +0900 Subject: [PATCH 002/191] include config.h to pull HAVE_STRLCPY --- lib/util.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/util.h b/lib/util.h index fde681fa..3daaef8f 100644 --- a/lib/util.h +++ b/lib/util.h @@ -40,6 +40,7 @@ #include #include #include +#include "config.h" #include "compiler.h" #ifndef va_copy From 6289822d9a7e6a2461c563965e40c24454710801 Mon Sep 17 00:00:00 2001 From: Srijan Mishra Date: Sun, 7 Jul 2013 21:43:55 +0530 Subject: [PATCH 003/191] fixes #53 Rectification in installation instructions --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5b21934a..edff3f03 100644 --- a/README.md +++ b/README.md @@ -50,10 +50,10 @@ The switch makes use of the NetBee library to parse packets, so we need to insta $ sudo ldconfig ``` -7. Put the folder `nbeesrc/include` in the `/usr/include` +7. Put the contens of folder `nbeesrc/include` in the `/usr/include` ``` - $ sudo cp -R ../include /usr/include + $ sudo cp -R ../include/* /usr/include/ ``` ## Building From 7c6f4d45272499f8b66907692c7e36f569836629 Mon Sep 17 00:00:00 2001 From: Simhon Doctori Date: Sun, 8 Sep 2013 11:12:37 +0200 Subject: [PATCH 004/191] Create dpctl_parser.py A simple python utility which helps monitoring and debugging the flows set at the switch (using OF1.3). It displays the flows per table in a more convinient way. It uses the dpctl tool to send the flow stats req. To run the application simply supply the datapath used, for example: pyhon2.7 dpctl_parser.py unix:/var/run/dp0 --- utilities/dpctl_parser.py | 104 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 utilities/dpctl_parser.py diff --git a/utilities/dpctl_parser.py b/utilities/dpctl_parser.py new file mode 100644 index 00000000..37b9d9ce --- /dev/null +++ b/utilities/dpctl_parser.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python2.7 +import os +import subprocess +import sys +import json +import re +import ast +# +# A simple python utility which helps monitoring and debugging +# the flows set at the switch (using OF1.3). It displays the flows per +# table in a more convinient way. +# It uses the dpctl tool to send the flow stats req. +# +# To run the application simply supply the datapath used, for example: +# +# pyhon2.7 dpctl_parser.py unix:/var/run/dp0 +# +# Enjoy... +# +# Written by Simhon Doctori. +# For any issues please send reqs to simhond@gmail.com +# +# Regular expression to parse the output +first_parse = re.compile(r'^stat_repl\{type="flow", flags="0x0", stats=\[') +flow_parse = re.compile(r'(\{table="[0-9]+",\s?match="oxm\{[.A-Fa-z\s?+,"0-9:=_-]+\}",\s?dur_s="[0-9]+",\s?dur_ns="[0-9]+",\s?prio="[0-9]+",\s?idle_to="[0-9]+",\s?hard_to="[0-9]+",\s?cookie="0x[0-9a-fA-F]+",\s?pkt_cnt="[0-9]+",\s?byte_cnt="[0-9]+",\s?insts=\[((apply\{acts=\[[A-Fa-z,\s\{\}"0-9:\.=_-]*\]\})?(write\{acts=\[[A-Fa-z,\s\{\}"0-9:\.=_-]*\]\})?(,\s)?(meta\{meta="0x[0-9a-fA-F]+", mask="0x[0-9a-fA-F]+"\})?(,\s)?(goto\{table="[0-9]+"\})?)\]\})+') +flow_parse_values = re.compile(r'(\{table="(?P[0-9]+)",\s?match="oxm\{(?P[A-Fa-z,\s\?+,"0-9:\.=_-]+)\}",\s?dur_s="(?P[0-9]+)",\s?dur_ns="(?P[0-9]+)",\s?prio="(?P[0-9]+)",\s?idle_to="(?P[0-9]+)",\s?hard_to="[0-9]+",\s?cookie="(?P0x[0-9a-fA-F]+)",\s?pkt_cnt="(?P[0-9]+)",\s?byte_cnt="(?P[0-9]+)",\s?insts=\[(?P(apply\{acts=\[[A-Fa-z,\s\{\}"0-9:\.=_-]*\]\})?(write\{acts=\[[A-Fa-z,\s\{\}"0-9:\.=_-]*\]\})?(,\s)?(meta\{meta="0x[0-9a-fA-F]+", mask="0x[0-9a-fA-F]+"\})?(,\s)?(goto\{table="[0-9]+"\})?)\]\})+') + + + +def process_flow (ix,flow): + new_flow = {} + if flow_parse_values.match(flow): + new_flow['table'] = flow_parse_values.search(flow).group('table') + new_flow['match'] = flow_parse_values.search(flow).group('match') + new_flow['dur_s'] = flow_parse_values.search(flow).group('dur_s') + new_flow['prio'] = flow_parse_values.search(flow).group('prio') + new_flow['dur_ns'] = flow_parse_values.search(flow).group('dur_ns') + new_flow['idle_to'] = flow_parse_values.search(flow).group('idle_to') + new_flow['cookie'] = flow_parse_values.search(flow).group('cookie') + new_flow['pkts'] = flow_parse_values.search(flow).group('pkts') + new_flow['bytes'] = flow_parse_values.search(flow).group('bytes') + new_flow['insts'] = flow_parse_values.search(flow).group('insts') + #print 'Flow {0} ->'.format(ix),new_flow + return new_flow + + + +def do_parse(line): + print 'received input is:' + #print line + print '\nstart parsing...' + m = first_parse.match(line) + if m: + new_str = line[m.end():len(line)-2] + #print 'new str:',new_str + #print 'findall:',flow_parse.findall(new_str) + cnt = 0 + for x in flow_parse.findall(new_str): + cnt += 1 + #print 'entry number {0} :\n'.format(cnt),x[0] + flow_lists.extend([process_flow(cnt,x[0])]) + else: + print 'match not found' + + +def parse_list(): + last_table_id = -1 + for x in flow_lists: + table_id = x['table'] + if table_to_parse!=-1 and table_to_parse!=table_id: + continue + if last_table_id ./dpctl_output") +#print 'parsing the output file' + +with open("./dpctl_output") as f: + for line in f: + if 'stat_repl' in line: + do_parse(line) +parse_list() +#print 'delete the output file' +os.system("rm -rf ./dpctl_output") +print '\n\nExit' From 4b72b92190e1111d1c1dd506dd78d6512e8f493d Mon Sep 17 00:00:00 2001 From: ederlf Date: Fri, 13 Sep 2013 09:51:33 -0300 Subject: [PATCH 005/191] Fix mistake on generation_id calculation and return the current generation id in case of OFPCR_ROLE_NOCHANGE. Fix suggested by shh0613 --- udatapath/datapath.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 7e002199..c8a46ac5 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -586,7 +586,7 @@ dp_handle_set_desc(struct datapath *dp, struct ofl_exp_openflow_msg_set_dp_desc static ofl_err dp_check_generation_id(struct datapath *dp, uint64_t new_gen_id){ - if(dp->generation_id >= 0 && ((uint64_t)(dp->generation_id - new_gen_id) < 0) ) + if(dp->generation_id >= 0 && ((uint64_t)(new_gen_id - dp->generation_id) < 0) ) return ofl_error(OFPET_ROLE_REQUEST_FAILED, OFPRRFC_STALE); else dp->generation_id = new_gen_id; return 0; @@ -596,10 +596,12 @@ dp_check_generation_id(struct datapath *dp, uint64_t new_gen_id){ ofl_err dp_handle_role_request(struct datapath *dp, struct ofl_msg_role_request *msg, const struct sender *sender) { - uint32_t role = msg->role; + uint32_t role = msg->role; + uint64_t generation_id = msg->generation_id; switch (msg->role) { case OFPCR_ROLE_NOCHANGE:{ role = sender->remote->role; + generation_id = dp->generation_id; break; } case OFPCR_ROLE_EQUAL: { @@ -641,7 +643,7 @@ dp_handle_role_request(struct datapath *dp, struct ofl_msg_role_request *msg, struct ofl_msg_role_request reply = {{.type = OFPT_ROLE_REPLY}, .role = role, - .generation_id = msg->generation_id}; + .generation_id = generation_id}; dp_send_message(dp, (struct ofl_msg_header *)&reply, sender); } From 899e5c232af9984ce3bd6789f0387e17357ef697 Mon Sep 17 00:00:00 2001 From: ederlf Date: Fri, 13 Sep 2013 10:45:15 -0300 Subject: [PATCH 006/191] Fix set_field actions for ARP and MPLS fields --- udatapath/dp_actions.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index ea176513..c18c00a4 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -235,14 +235,19 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) pkt->handle_std->proto->icmp->icmp_code = *act->field->value; break; } - case OXM_OF_ARP_OP: + case OXM_OF_ARP_OP: { + pkt->handle_std->proto->arp->ar_op = htons(*((uint16_t*) act->field->value)); + break; + } case OXM_OF_ARP_SPA:{ pkt->handle_std->proto->arp->ar_spa = *((uint32_t*) act->field->value); + break; } case OXM_OF_ARP_TPA:{ pkt->handle_std->proto->arp->ar_tpa = *((uint32_t*) act->field->value); + break; } case OXM_OF_ARP_SHA:{ memcpy(pkt->handle_std->proto->arp->ar_sha, @@ -252,17 +257,17 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) case OXM_OF_ARP_THA:{ memcpy(pkt->handle_std->proto->arp->ar_tha, act->field->value, OXM_LENGTH(act->field->header)); - break; + break; } case OXM_OF_IPV6_SRC:{ memcpy(&pkt->handle_std->proto->ipv6->ipv6_src, act->field->value, OXM_LENGTH(act->field->header)); - break; + break; } case OXM_OF_IPV6_DST:{ memcpy(&pkt->handle_std->proto->ipv6->ipv6_dst, act->field->value, OXM_LENGTH(act->field->header)); - break; + break; } case OXM_OF_IPV6_FLABEL:{ struct ipv6_header *ipv6 = (struct ipv6_header*) @@ -311,7 +316,8 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) if(opt->type == ND_OPT_TLL){ memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); - } break; + } + break; } case OXM_OF_MPLS_LABEL:{ struct mpls_header *mpls = pkt->handle_std->proto->mpls; @@ -324,17 +330,20 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) struct mpls_header *mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_TC_MASK)) | ntohl((*act->field->value << MPLS_TC_SHIFT) & MPLS_TC_MASK); + break; } case OXM_OF_MPLS_BOS:{ struct mpls_header *mpls = pkt->handle_std->proto->mpls; mpls->fields = (mpls->fields & ~ntohl(MPLS_S_MASK)) | ntohl((*act->field->value << MPLS_S_SHIFT) & MPLS_S_MASK); + break; } case OXM_OF_PBB_ISID :{ struct pbb_header *pbb = pkt->handle_std->proto->pbb; uint32_t v = *((uint32_t*) act->field->value); pbb->id = (pbb->id & ~ntohl(PBB_ISID_MASK)) | ntohl(v & PBB_ISID_MASK); + break; } default: VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to set unknow field."); From 0bb2cf8b0ba1da8950c117d6e9ea57ee646fbd43 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Tue, 17 Sep 2013 15:53:00 +0900 Subject: [PATCH 007/191] note more of required packages --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index edff3f03..78022504 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ The switch makes use of the NetBee library to parse packets, so we need to insta 1. Install the following packages: ``` - $ sudo apt-get install cmake libpcap-dev libxerces-c2-dev libpcre3-dev flex bison + $ sudo apt-get install cmake libpcap-dev libxerces-c2-dev libpcre3-dev flex bison pkg-config autoconf libtool ``` 2. Download and unpack the source code from: http://www.nbee.org/download/nbeesrc-12-05-16.php From 2c09414837ef30be5a47b13dd22c8dc30a7c57c7 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Takashi Date: Tue, 17 Sep 2013 16:10:29 +0900 Subject: [PATCH 008/191] libboost-dev seems to be necessary --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 78022504..4136f564 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ The switch makes use of the NetBee library to parse packets, so we need to insta 1. Install the following packages: ``` - $ sudo apt-get install cmake libpcap-dev libxerces-c2-dev libpcre3-dev flex bison pkg-config autoconf libtool + $ sudo apt-get install cmake libpcap-dev libxerces-c2-dev libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev ``` 2. Download and unpack the source code from: http://www.nbee.org/download/nbeesrc-12-05-16.php From cd572bd4d0698f9dd388014bd8a85ed53959e84d Mon Sep 17 00:00:00 2001 From: ederlf Date: Wed, 18 Sep 2013 11:15:24 -0300 Subject: [PATCH 009/191] Fix for pbb isid parsing --- customnetpdl.xml | 2 +- nbee_link/nbee_link.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/customnetpdl.xml b/customnetpdl.xml index 77b4a713..89796c45 100644 --- a/customnetpdl.xml +++ b/customnetpdl.xml @@ -1151,7 +1151,7 @@ --> - + diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index 756fd48a..194f8eb0 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -276,6 +276,12 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str m_value = (m_value & MPLS_S_MASK) >> MPLS_S_SHIFT; ofl_structs_match_put8(pktout, header, m_value); } + else if (header == OXM_OF_PBB_ISID){ + uint32_t m_value; + sscanf(field->Value, "%x", &m_value); + m_value = (m_value & PBB_ISID_MASK); + ofl_structs_match_put32(pktout, header, m_value); + } /*TODO: Add IPV6_FLABEL_SHIFT to lib/packets.h*/ /*else if (header == OXM_OF_IPV6_FLABEL){ uint32_t m_value; @@ -400,7 +406,7 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ETH_TYPE); } - else if ((protocol_Name.compare("vlan") == 0 || protocol_Name.compare("pbb_b") == 0)) + else if ((protocol_Name.compare("vlan") == 0)) { if(pkt_proto->vlan_last == NULL){ pkt_proto->vlan = pkt_proto->vlan_last = (struct vlan_header *) ((uint8_t*) pktin->data + proto->Position); @@ -443,7 +449,7 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ARP_TPA); } - else if (protocol_Name.compare("pbb_s") == 0 && pkt_proto->pbb == NULL) + else if (protocol_Name.compare("pbb") == 0 && pkt_proto->pbb == NULL) { pkt_proto->pbb = (struct pbb_header *) ((uint8_t*) pktin->data + proto->Position); PDMLReader->GetPDMLField(proto->Name, (char*) "isid", proto->FirstField, &field); From e4a6a138395f1660b5b2cb9fcae0c8859b246a53 Mon Sep 17 00:00:00 2001 From: ederlf Date: Thu, 19 Sep 2013 16:38:58 -0300 Subject: [PATCH 010/191] Fix: Init hash map when unpacking match. Without this step, check for match overlap on all oxm matches causes segmentation fault due to unitialized hash map. Fix: When parsing IPv6, increase the lenght of the match. --- nbee_link/nbee_link.cpp | 1 + oflib/ofl-structs-unpack.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index 194f8eb0..f824f442 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -501,6 +501,7 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk hmap_insert_fast(&pktout->match_fields, &EH_field->hmap_node, hash_int(EH_field->header, 0)); + pktout->header.length += 6; PDMLReader->GetPDMLField(proto->Name, (char*) "src", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_SRC); PDMLReader->GetPDMLField(proto->Name, (char*) "dst", proto->FirstField, &field); diff --git a/oflib/ofl-structs-unpack.c b/oflib/ofl-structs-unpack.c index fbf54f83..3134a4cf 100644 --- a/oflib/ofl-structs-unpack.c +++ b/oflib/ofl-structs-unpack.c @@ -1146,7 +1146,8 @@ ofl_structs_oxm_match_unpack(struct ofp_match* src, uint8_t* buf, size_t *len, s } else { m->header.length = 0; - m->header.type = ntohs(src->type); + m->header.type = ntohs(src->type); + m->match_fields = (struct hmap) HMAP_INITIALIZER(&m->match_fields); } ofpbuf_delete(b); *dst = m; @@ -1158,9 +1159,7 @@ ofl_structs_match_unpack(struct ofp_match *src,uint8_t * buf, size_t *len, struc switch (ntohs(src->type)) { case (OFPMT_OXM): { - - return ofl_structs_oxm_match_unpack(src, buf, len, (struct ofl_match**) dst ); - + return ofl_structs_oxm_match_unpack(src, buf, len, (struct ofl_match**) dst ); } default: { if (exp == NULL || exp->match == NULL || exp->match->unpack == NULL) { From 1d7855e2f5dc4c532e8103bac95049bd4275b399 Mon Sep 17 00:00:00 2001 From: Marco Canini Date: Sun, 20 Oct 2013 17:07:54 -0200 Subject: [PATCH 011/191] Fix a buffer mismanagement bug that causes the udatapath to crash if the packet contains a VLAN id. --- lib/netdev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/netdev.c b/lib/netdev.c index 3452d6af..2674468d 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -1005,7 +1005,6 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) continue; /* VLAN tag found. Shift MAC addresses down and insert VLAN tag */ /* Create headroom for the VLAN tag */ - ofpbuf_reserve(buffer, VLAN_HEADER_LEN); ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN); memmove(buffer->data, (uint8_t*)buffer->data+VLAN_HEADER_LEN, ETH_ALEN * 2); tag = (struct vlan_tag *)((uint8_t*)buffer->data + ETH_ALEN * 2); From b63c9af3499877955868dc725e7a25cf48e4ef8f Mon Sep 17 00:00:00 2001 From: ederlf Date: Tue, 29 Oct 2013 20:09:25 -0200 Subject: [PATCH 012/191] Unpack missing in_port member to packet_out unpack. --- oflib/ofl-messages-unpack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 9e180ce1..7c131757 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -384,7 +384,7 @@ ofl_msg_unpack_packet_out(struct ofp_header *src, size_t *len, struct ofl_msg_he dp = (struct ofl_msg_packet_out *)malloc(sizeof(struct ofl_msg_packet_out)); dp->buffer_id = ntohl(sp->buffer_id); - + dp->in_port = ntohl(sp->in_port); if (*len < ntohs(sp->actions_len)) { OFL_LOG_WARN(LOG_MODULE, "Received PACKET_OUT message has invalid action length (%zu).", *len); free(dp); From f4cdf1c1b051dbcf5a0ac9f2cb5368631e315f26 Mon Sep 17 00:00:00 2001 From: Marco Canini Date: Fri, 8 Nov 2013 20:56:39 -0200 Subject: [PATCH 013/191] Fix a case switch that is not handling unknown instruction types with a default case, leading to a crash if the instruction type is unknown. --- oflib/ofl-structs-unpack.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/oflib/ofl-structs-unpack.c b/oflib/ofl-structs-unpack.c index 3134a4cf..755f9075 100644 --- a/oflib/ofl-structs-unpack.c +++ b/oflib/ofl-structs-unpack.c @@ -192,6 +192,9 @@ ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct } break; } + default: + OFL_LOG_WARN(LOG_MODULE, "The received instruction type (%zu) is invalid.", ntohs(src->type)); + return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNKNOWN_INST); } // must set type before check, so free works correctly From 4e725bc011681de23f3552b800a6d1f354f2d023 Mon Sep 17 00:00:00 2001 From: Marco Canini Date: Fri, 8 Nov 2013 21:56:00 -0200 Subject: [PATCH 014/191] Add a simple utility program useful for debugging. The program prints the content of OF messages stored in a file. I use a combination of tcpdump and tcpflow to dump OF messages. --- utilities/automake.mk | 6 +++ utilities/ofp-read.c | 106 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 utilities/ofp-read.c diff --git a/utilities/automake.mk b/utilities/automake.mk index 85592373..f85561c5 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -5,6 +5,8 @@ bin_PROGRAMS += \ utilities/ofp-kill bin_SCRIPTS += utilities/ofp-pki noinst_SCRIPTS += utilities/ofp-pki-cgi utilities/ofp-parse-leaks +noinst_PROGRAMS += \ + utilities/ofp-read EXTRA_DIST += \ utilities/dpctl.8.in \ @@ -43,3 +45,7 @@ utilities_ofp_discover_LDADD = lib/libopenflow.a utilities_ofp_kill_SOURCES = utilities/ofp-kill.c utilities_ofp_kill_LDADD = lib/libopenflow.a + +utilities_ofp_read_SOURCES = utilities/ofp-read.c +utilities_ofp_read_LDADD = lib/libopenflow.a oflib/liboflib.a + diff --git a/utilities/ofp-read.c b/utilities/ofp-read.c new file mode 100644 index 00000000..bbe7b1df --- /dev/null +++ b/utilities/ofp-read.c @@ -0,0 +1,106 @@ +/* Copyright (c) 2013, Marco Canini + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the Ericsson Research nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * 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 HOLDER 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. + * + */ + +#include +#include +#include + +#include "oflib/ofl-messages.h" + +#include "timeval.h" +#include "vlog.h" + +static size_t read_all(FILE *file, uint8_t **buf) +{ + size_t buf_len; + uint8_t *data; + *buf = NULL; + + fseek(file, 0, SEEK_END); + buf_len = ftell(file); + rewind(file); + + data = (uint8_t*) malloc(buf_len); + fread(data, buf_len, 1, file); + if (ferror(file)) { + fprintf(stderr, "Cannot read msg file.\n"); + return -1; + } + *buf = data; + return buf_len; +} + +int main(int argc, char **argv) +{ + uint8_t *buf ,*buf0; + size_t buf_len = 0; + ofl_err err; + struct ofl_msg_header *msg = NULL; + uint32_t xid; + FILE *msg_file; + struct ofp_header *oh; + + if (argc < 2) { + fprintf(stderr, "Expecting msg file.\n"); + return 1; + } + + time_init(); + vlog_init(); + vlog_set_verbosity(NULL); + + msg_file = fopen(argv[1], "r"); + if (msg_file == NULL) { + fprintf(stderr, "Cannot open msg file.\n"); + return 1; + } + buf_len = read_all(msg_file, &buf); + buf0 = buf; + //printf("buf len = %ld\n", buf_len); + + while (buf_len > 0) { + oh = (struct ofp_header *)buf; + err = ofl_msg_unpack(buf, ntohs(oh->length), &msg, &xid, NULL); + if (err == 0) { + //printf("Success!\n"); + ofl_msg_print(stdout, msg, NULL); + printf("\n\n"); + ofl_msg_free(msg, NULL); + } else { + free(buf); + printf("Failed :-( error type: %d code %d\n", ofl_error_type(err), ofl_error_code(err)); + return 1; + } + buf_len -= ntohs(oh->length); + buf += ntohs(oh->length); + } + free(buf0); + return 0; +} + From 88b2d3fea8fd71abc67a311d300a2cd35282773a Mon Sep 17 00:00:00 2001 From: Marco Canini Date: Fri, 8 Nov 2013 21:59:59 -0200 Subject: [PATCH 015/191] C&P --- utilities/ofp-read.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/ofp-read.c b/utilities/ofp-read.c index bbe7b1df..eb18b577 100644 --- a/utilities/ofp-read.c +++ b/utilities/ofp-read.c @@ -9,7 +9,7 @@ * * 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. - * * Neither the name of the Ericsson Research nor the names of its + * * Neither the name of the software nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * From 32df7765d2ee131aa2efdbd6c832d890d7dd7849 Mon Sep 17 00:00:00 2001 From: ederlf Date: Sun, 10 Nov 2013 22:01:30 -0200 Subject: [PATCH 016/191] Fix set_field for VLAN fields. VLAN presence is not guaranteed by match prerequisites, so check for the field existence. --- udatapath/dp_actions.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index c18c00a4..e59b9211 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -100,17 +100,23 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) } case OXM_OF_VLAN_VID:{ struct vlan_header *vlan = pkt->handle_std->proto->vlan; - uint16_t v = (*(uint16_t*)act->field->value); - vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) - | (v & VLAN_VID_MASK)); + /* VLAN existence is no guaranteed by match prerquisite*/ + if(vlan != NULL){ + uint16_t v = (*(uint16_t*)act->field->value); + vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) + | (v & VLAN_VID_MASK)); + + } break; } case OXM_OF_VLAN_PCP:{ struct vlan_header *vlan = pkt->handle_std->proto->vlan; - - vlan->vlan_tci = (vlan->vlan_tci & ~htons(VLAN_PCP_MASK)) - | htons(*act->field->value << VLAN_PCP_SHIFT); - break; + /* VLAN existence is no guaranteed by match prerquisite*/ + if(vlan != NULL){ + vlan->vlan_tci = (vlan->vlan_tci & ~htons(VLAN_PCP_MASK)) + | htons(*act->field->value << VLAN_PCP_SHIFT); + break; + } } case OXM_OF_IP_DSCP:{ struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; From c4df4d172267911d373186c579a7b0459e78724d Mon Sep 17 00:00:00 2001 From: Marco Canini Date: Tue, 12 Nov 2013 21:39:57 +0100 Subject: [PATCH 017/191] Bump max entries to 4096. --- udatapath/flow_table.h | 2 +- udatapath/group_table.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/udatapath/flow_table.h b/udatapath/flow_table.h index 9210095a..b1b1f220 100644 --- a/udatapath/flow_table.h +++ b/udatapath/flow_table.h @@ -37,7 +37,7 @@ #include "timeval.h" -#define FLOW_TABLE_MAX_ENTRIES 1024 +#define FLOW_TABLE_MAX_ENTRIES 4096 #define TABLE_FEATURES_NUM 14 // EEDJAS: N_OXM_FIELDS is an enum value exported by oxm-match.h via ofl-structs.h // #define N_OXM_FIELDS 40 diff --git a/udatapath/group_table.h b/udatapath/group_table.h index 2289ab45..4ef564f8 100644 --- a/udatapath/group_table.h +++ b/udatapath/group_table.h @@ -44,7 +44,7 @@ ****************************************************************************/ -#define GROUP_TABLE_MAX_ENTRIES 1024 +#define GROUP_TABLE_MAX_ENTRIES 4096 #define GROUP_TABLE_MAX_BUCKETS 8192 struct datapath; From 4a54a39ce474f048285b4900bec66171d2adb17d Mon Sep 17 00:00:00 2001 From: Marco Canini Date: Fri, 22 Nov 2013 01:57:01 +0100 Subject: [PATCH 018/191] Fix conformance to specifications for Set-Field VLAN_VID OpenFlow Specification 1.3.3 (https://www.opennetworking.org/images/stories/downloads/sdn-resources/onf-specifications/openflow/openflow-spec-v1.3.3.pdf), p. 65: "The value in the payload of the OXM TLV must be valid, in particular the OFPVID_PRESENT bit must be set in OXM_OF_VLAN_VID set-field actions." --- utilities/dpctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index dd34dff8..9f64a220 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -1660,6 +1660,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { else { act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); act->field->header = OXM_OF_VLAN_VID; + *dl_vlan = *dl_vlan | OFPVID_PRESENT; act->field->value = (uint8_t*) dl_vlan; } return 0; From 54d00134ef26bdfe28a8fe8214ff58f9fbc2f2aa Mon Sep 17 00:00:00 2001 From: Marco Canini Date: Fri, 22 Nov 2013 01:57:01 +0100 Subject: [PATCH 019/191] Fix conformance to specifications for Set-Field VLAN_VID OpenFlow Specification 1.3.3 (https://www.opennetworking.org/images/stories/downloads/sdn-resources/onf-specifications/openflow/openflow-spec-v1.3.3.pdf), p. 65: "The value in the payload of the OXM TLV must be valid, in particular the OFPVID_PRESENT bit must be set in OXM_OF_VLAN_VID set-field actions." --- utilities/dpctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index dd34dff8..9f64a220 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -1660,6 +1660,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { else { act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); act->field->header = OXM_OF_VLAN_VID; + *dl_vlan = *dl_vlan | OFPVID_PRESENT; act->field->value = (uint8_t*) dl_vlan; } return 0; From 2200d52c6b609e1d6ca7d4ecff13e5a95cf96ff9 Mon Sep 17 00:00:00 2001 From: cloudysunny14 Date: Sun, 22 Dec 2013 16:01:23 +0900 Subject: [PATCH 020/191] Fix incorrect checksum value due to the Remark DSCP --- udatapath/meter_entry.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index 2bea3739..fc46f2a5 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -30,6 +30,7 @@ */ #include +#include "csum.h" #include "flow_entry.h" #include "meter_entry.h" #include "meter_table.h" @@ -226,11 +227,16 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ } case OFPMBT_DSCP_REMARK:{ struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; - // descrease dscp in ipv4 header - uint8_t new_dscp = ((*pkt)->handle_std->proto->ipv4->ip_tos >> 5) - band_header->prec_level; - (*pkt)->handle_std->proto->ipv4->ip_tos = (new_dscp << 5) | ((*pkt)->handle_std->proto->ipv4->ip_tos & 0x1f); + // descrease dscp in ipv4 header + struct ip_header *ipv4 = (*pkt)->handle_std->proto->ipv4; + uint8_t new_dscp = (ipv4->ip_tos >> 5) - band_header->prec_level; + uint8_t new_tos = (new_dscp << 5 ) | (ipv4->ip_tos & 0x1f); + uint16_t old_val = htons((ipv4->ip_ihl_ver >> 8) + ipv4->ip_tos); + uint16_t new_val = htons((ipv4->ip_ihl_ver >> 8) + new_tos); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_tos = new_tos; break; - } + } case OFPMBT_EXPERIMENTER:{ break; } From 9b9286765fc3507d15904962431d0e061042d877 Mon Sep 17 00:00:00 2001 From: codeshredder Date: Wed, 25 Dec 2013 09:35:04 +0800 Subject: [PATCH 021/191] Update dp_actions.c --- udatapath/dp_actions.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index e59b9211..a0443594 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -183,36 +183,34 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) } case OXM_OF_TCP_SRC:{ struct tcp_header *tcp = pkt->handle_std->proto->tcp; - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src,*v); - memcpy(&tcp->tcp_src, v, OXM_LENGTH(act->field->header)); + uint16_t v = htons(*(uint16_t*) act->field->value); + tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src, v); + memcpy(&tcp->tcp_src, &v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_TCP_DST:{ struct tcp_header *tcp = pkt->handle_std->proto->tcp; - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst,*v); - memcpy(&tcp->tcp_dst, v, OXM_LENGTH(act->field->header)); + uint16_t v = htons(*(uint16_t*) act->field->value); + tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst, v); + memcpy(&tcp->tcp_dst, &v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_UDP_SRC:{ struct udp_header *udp = pkt->handle_std->proto->udp; - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, *v); - memcpy(&udp->udp_src, v, OXM_LENGTH(act->field->header)); + uint16_t v = htons(*(uint16_t*) act->field->value); + udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_src, v); + memcpy(&udp->udp_src, &v, OXM_LENGTH(act->field->header)); + break; } case OXM_OF_UDP_DST:{ struct udp_header *udp = pkt->handle_std->proto->udp; - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, *v); - memcpy(&udp->udp_dst, v, OXM_LENGTH(act->field->header)); + uint16_t v = htons(*(uint16_t*) act->field->value); + udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, v); + memcpy(&udp->udp_dst, &v, OXM_LENGTH(act->field->header)); + break; } /*TODO recalculate SCTP checksum*/ @@ -1097,4 +1095,4 @@ dp_actions_check_set_field_req(struct ofl_msg_flow_mod *msg, size_t actions_num, } } return 0; -} \ No newline at end of file +} From 2da1f4415dd56c0561fa779ffec44ea7cce4ebfe Mon Sep 17 00:00:00 2001 From: codeshredder Date: Wed, 25 Dec 2013 09:37:24 +0800 Subject: [PATCH 022/191] Update dpctl.c --- utilities/dpctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 9f64a220..e70fbe3c 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -1814,7 +1814,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { } if (strncmp(token, MATCH_TP_DST KEY_VAL2, strlen(MATCH_TP_DST KEY_VAL2)) == 0) { uint16_t* tp_dst = xmalloc(2); - if (parse16(token + strlen(MATCH_TP_SRC KEY_VAL2), NULL, 0, 0xffff, tp_dst)) { + if (parse16(token + strlen(MATCH_TP_DST KEY_VAL2), NULL, 0, 0xffff, tp_dst)) { ofp_fatal(0, "Error parsing tcp_src: %s.", token); }else{ act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); From a8095f5e687e6a4e1f611244db6e89e32cabb072 Mon Sep 17 00:00:00 2001 From: codeshredder Date: Wed, 25 Dec 2013 09:38:47 +0800 Subject: [PATCH 023/191] Update dpctl.c --- utilities/dpctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index e70fbe3c..46c379ae 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -2111,7 +2111,7 @@ parse_flow_stat_args(char *str, struct ofl_msg_multipart_request_flow *req) { continue; } if (strncmp(token, FLOW_MOD_COOKIE_MASK KEY_VAL, strlen(FLOW_MOD_COOKIE_MASK KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { + if (sscanf(token, FLOW_MOD_COOKIE_MASK KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { ofp_fatal(0, "Error parsing flow_stat cookie mask: %s.", token); } continue; From fccc658caca3158e012e4a2d36395f14ba3fdbe1 Mon Sep 17 00:00:00 2001 From: codeshredder Date: Wed, 25 Dec 2013 09:42:46 +0800 Subject: [PATCH 024/191] Update dpctl.c --- utilities/dpctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 46c379ae..f25c5f3d 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -2160,7 +2160,7 @@ parse_flow_mod_args(char *str, struct ofl_msg_flow_mod *req) { continue; } if (strncmp(token, FLOW_MOD_COOKIE_MASK KEY_VAL, strlen(FLOW_MOD_COOKIE_MASK KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { + if (sscanf(token, FLOW_MOD_COOKIE_MASK KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { ofp_fatal(0, "Error parsing flow_mod cookie mask: %s.", token); } continue; From 4a4e89a28a008ced214342302708ef5a4317f29d Mon Sep 17 00:00:00 2001 From: cloudysunny14 Date: Wed, 15 Jan 2014 18:48:52 +0900 Subject: [PATCH 025/191] Fix caluculate inccorect checksum when Action Set-Field DSCP value and remark dscp. --- nbee_link/nbee_link.cpp | 4 ++-- udatapath/dp_actions.c | 11 ++++++----- udatapath/meter_entry.c | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index f824f442..1c440895 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -249,13 +249,13 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str else if(header == OXM_OF_IP_DSCP){ uint8_t m_value; sscanf(field->Value, "%hhx", &m_value); - m_value = m_value & IP_DSCP_MASK; + m_value = (m_value & IP_DSCP_MASK) >> 2; ofl_structs_match_put8(pktout, header, m_value); } else if(header == OXM_OF_IP_ECN){ uint8_t m_value; sscanf(field->Value, "%hhx", &m_value); - m_value = m_value & OXM_OF_IP_ECN; + m_value = m_value & IP_ECN_MASK; ofl_structs_match_put8(pktout, header, m_value); } else if(header == OXM_OF_MPLS_LABEL){ diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index a0443594..92506094 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -122,9 +122,9 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; uint8_t tos = (ipv4->ip_tos & ~IP_DSCP_MASK) | (*act->field->value << 2); - - ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, (uint16_t) - (ipv4->ip_tos), (uint16_t)tos); + uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); + uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + tos); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); ipv4->ip_tos = tos; break; } @@ -132,8 +132,9 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; uint8_t tos = (ipv4->ip_tos & ~IP_ECN_MASK) | (*act->field->value & IP_ECN_MASK); - ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, (uint16_t) - (ipv4->ip_tos), (uint16_t)tos); + uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); + uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + tos); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); ipv4->ip_tos = tos; break; } diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index fc46f2a5..da1efdbb 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -231,8 +231,8 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ struct ip_header *ipv4 = (*pkt)->handle_std->proto->ipv4; uint8_t new_dscp = (ipv4->ip_tos >> 5) - band_header->prec_level; uint8_t new_tos = (new_dscp << 5 ) | (ipv4->ip_tos & 0x1f); - uint16_t old_val = htons((ipv4->ip_ihl_ver >> 8) + ipv4->ip_tos); - uint16_t new_val = htons((ipv4->ip_ihl_ver >> 8) + new_tos); + uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); + uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + new_tos); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); ipv4->ip_tos = new_tos; break; From 519b1c6b66f45b702d2edafcdd14209528663a72 Mon Sep 17 00:00:00 2001 From: codeshredder Date: Sat, 18 Jan 2014 10:34:37 +0800 Subject: [PATCH 026/191] operation for cookie_mask error operation for cookie_mask,not for cookie --- utilities/dpctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index f25c5f3d..a0418235 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -2111,7 +2111,7 @@ parse_flow_stat_args(char *str, struct ofl_msg_multipart_request_flow *req) { continue; } if (strncmp(token, FLOW_MOD_COOKIE_MASK KEY_VAL, strlen(FLOW_MOD_COOKIE_MASK KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE_MASK KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { + if (sscanf(token, FLOW_MOD_COOKIE_MASK KEY_VAL "0x%"SCNx64"", &(req->cookie_mask)) != 1) { ofp_fatal(0, "Error parsing flow_stat cookie mask: %s.", token); } continue; @@ -2160,7 +2160,7 @@ parse_flow_mod_args(char *str, struct ofl_msg_flow_mod *req) { continue; } if (strncmp(token, FLOW_MOD_COOKIE_MASK KEY_VAL, strlen(FLOW_MOD_COOKIE_MASK KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE_MASK KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { + if (sscanf(token, FLOW_MOD_COOKIE_MASK KEY_VAL "0x%"SCNx64"", &(req->cookie_mask)) != 1) { ofp_fatal(0, "Error parsing flow_mod cookie mask: %s.", token); } continue; From 684a76c707ee211209d1798a0731b12724585099 Mon Sep 17 00:00:00 2001 From: cloudysunny14 Date: Mon, 27 Jan 2014 20:47:37 +0900 Subject: [PATCH 027/191] Match field MPLS TC and MPLS BOS doesn't work --- nbee_link/nbee_link.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index 1c440895..2693f3bb 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -265,14 +265,14 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str ofl_structs_match_put32(pktout, header, m_value); } else if (header == OXM_OF_MPLS_TC){ - uint8_t m_value; - sscanf(field->Value, "%hhx", &m_value); + uint32_t m_value; + sscanf(field->Value, "%x", &m_value); m_value = (m_value & MPLS_TC_MASK) >> MPLS_TC_SHIFT; - ofl_structs_match_put32(pktout, header, m_value); + ofl_structs_match_put8(pktout, header, m_value); } else if (header == OXM_OF_MPLS_BOS){ - uint8_t m_value; - sscanf(field->Value, "%hhx", &m_value); + uint32_t m_value; + sscanf(field->Value, "%x", &m_value); m_value = (m_value & MPLS_S_MASK) >> MPLS_S_SHIFT; ofl_structs_match_put8(pktout, header, m_value); } From cea85b731e319feddf2744c59b9bacd996d4c2eb Mon Sep 17 00:00:00 2001 From: ederlf Date: Tue, 18 Feb 2014 17:23:40 -0300 Subject: [PATCH 028/191] Correct mask to print MPLS BOS match field --- oflib/ofl-structs-print.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index 76a7d3b8..09c80126 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -395,7 +395,7 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) fprintf(stream, "mpls_tc=\"%d\"", *f->value & 0x3); break; case OFPXMT_OFB_MPLS_BOS: - fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0xfe); + fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0x1); break; case OFPXMT_OFB_METADATA: fprintf(stream, "metadata=\"0x%llx\"", *((uint64_t*) f->value)); From f8cc42f8837ec287c8975fe56a595687d76e6faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Fri, 25 Apr 2014 08:23:15 -0300 Subject: [PATCH 029/191] Change Netbee version to the most recent The most recent Netbee version should fix the compilation issues on most recent Ubuntu versions. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4136f564..0840d631 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ The switch makes use of the NetBee library to parse packets, so we need to insta $ sudo apt-get install cmake libpcap-dev libxerces-c2-dev libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev ``` -2. Download and unpack the source code from: http://www.nbee.org/download/nbeesrc-12-05-16.php +2. Download the most recent Netbee version, and unpack the source code from:http://www.nbee.org/download/nbeesrc-jan-10-2013.php 3. Create the build system From 3a4654683ca98f331ea0491a99357884fbb1b448 Mon Sep 17 00:00:00 2001 From: Jan Skalny Date: Fri, 25 Apr 2014 17:24:01 +0200 Subject: [PATCH 030/191] Interfaces with different MTU can cause index OOB / segfault --- udatapath/dp_ports.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/udatapath/dp_ports.c b/udatapath/dp_ports.c index 684357ec..00c99783 100644 --- a/udatapath/dp_ports.c +++ b/udatapath/dp_ports.c @@ -229,6 +229,7 @@ void dp_ports_run(struct datapath *dp) { // static, so an unused buffer can be reused at the dp_ports_run call static struct ofpbuf *buffer = NULL; + int max_mtu = 0; struct sw_port *p, *pn; @@ -247,6 +248,16 @@ dp_ports_run(struct datapath *dp) { } #endif + // find largest MTU on our interfaces + // buffer is shared among all (idle) interfaces... + LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { + if (IS_HW_PORT(p)) + continue; + const int mtu = netdev_get_mtu(p->netdev); + if (mtu > max_mtu) + max_mtu = mtu; + } + LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { int error; @@ -259,8 +270,7 @@ dp_ports_run(struct datapath *dp) { * 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_with_headroom(hard_header + mtu, headroom); + buffer = ofpbuf_new_with_headroom(hard_header + max_mtu, headroom); } error = netdev_recv(p->netdev, buffer); if (error == ENETDOWN){ From d174464dcc414510990e38426e2e274a25330902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Sun, 4 May 2014 11:03:43 -0300 Subject: [PATCH 031/191] Update README.md Update contact information. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0840d631..77b918e9 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ Hiroyasu OHYAMA, correct URL of NetBee Library. *know if we forgot to add your name to the list of contributors!* # Contact -E-mail: Eder Leao Fernandes (ederlf@cpqd.com.br) +E-mail: Eder Leao Fernandes (ederleaofernandes at gmail . com) [ofp13]: https://www.opennetworking.org/images/stories/downloads/specification/openflow-spec-v1.3.0.pdf [ericssonsw11]: https://github.com/TrafficLab/of11softswitch From a40a1c2c51c1d7186e00d1fb40b4a14e95691561 Mon Sep 17 00:00:00 2001 From: Kiyonari Harigae Date: Mon, 2 Jun 2014 19:12:34 +0900 Subject: [PATCH 032/191] Conforms to the specifications of the OpenFlow 1.3.1 --- udatapath/meter_entry.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index da1efdbb..d3044681 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -229,8 +229,8 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; // descrease dscp in ipv4 header struct ip_header *ipv4 = (*pkt)->handle_std->proto->ipv4; - uint8_t new_dscp = (ipv4->ip_tos >> 5) - band_header->prec_level; - uint8_t new_tos = (new_dscp << 5 ) | (ipv4->ip_tos & 0x1f); + uint8_t new_dscp = (ipv4->ip_tos >> 3) + band_header->prec_level; + uint8_t new_tos = (new_dscp << 3 ) | (ipv4->ip_tos & 0x03); uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + new_tos); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); From ba99499b941883a213fa7981d5c1272bf37c21be Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 7 Feb 2014 14:17:11 -0800 Subject: [PATCH 033/191] Fix running out of array on oxm_ids[], use safer array lengths in table feat. --- udatapath/flow_table.c | 13 +++++++++++-- udatapath/flow_table.h | 6 +----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/udatapath/flow_table.c b/udatapath/flow_table.c index 5d236808..415c3399 100644 --- a/udatapath/flow_table.c +++ b/udatapath/flow_table.c @@ -55,21 +55,30 @@ uint32_t oxm_ids[]={OXM_OF_IN_PORT,OXM_OF_IN_PHY_PORT,OXM_OF_METADATA,OXM_OF_ET OXM_OF_IPV6_ND_TLL, OXM_OF_MPLS_LABEL, OXM_OF_MPLS_TC, OXM_OF_MPLS_BOS, OXM_OF_PBB_ISID, OXM_OF_TUNNEL_ID, OXM_OF_IPV6_EXTHDR}; +#define NUM_OXM_IDS (sizeof(oxm_ids) / sizeof(uint32_t)) +/* Do *NOT* use N_OXM_FIELDS, it's ligically wrong and can run over + * the oxm_ids array. Jean II */ + uint32_t wildcarded[] = {OXM_OF_METADATA, OXM_OF_ETH_DST, OXM_OF_ETH_SRC, OXM_OF_VLAN_VID, OXM_OF_IPV4_SRC, OXM_OF_IPV4_DST, OXM_OF_ARP_SPA, OXM_OF_ARP_TPA, OXM_OF_ARP_SHA, OXM_OF_ARP_THA, OXM_OF_IPV6_SRC, OXM_OF_IPV6_DST , OXM_OF_IPV6_FLABEL, OXM_OF_PBB_ISID, OXM_OF_TUNNEL_ID, OXM_OF_IPV6_EXTHDR}; +#define NUM_WILD_IDS (sizeof(wildcarded) / sizeof(uint32_t)) struct ofl_instruction_header instructions[] = { {OFPIT_GOTO_TABLE}, {OFPIT_WRITE_METADATA },{OFPIT_WRITE_ACTIONS},{OFPIT_APPLY_ACTIONS}, {OFPIT_CLEAR_ACTIONS},{OFPIT_METER}} ; +#define N_INSTRUCTIONS (sizeof(instructions) / sizeof(struct ofl_instruction_header)) + struct ofl_action_header actions[] = { {OFPAT_OUTPUT, 4}, {OFPAT_COPY_TTL_OUT, 4},{OFPAT_COPY_TTL_IN, 4},{OFPAT_SET_MPLS_TTL, 4}, {OFPAT_DEC_MPLS_TTL, 4},{OFPAT_PUSH_VLAN, 4},{OFPAT_POP_VLAN, 4}, {OFPAT_PUSH_MPLS, 4}, {OFPAT_POP_MPLS, 4},{OFPAT_SET_QUEUE, 4}, {OFPAT_GROUP, 4}, {OFPAT_SET_NW_TTL, 4}, {OFPAT_DEC_NW_TTL, 4}, {OFPAT_SET_FIELD, 4}, {OFPAT_PUSH_PBB, 4}, {OFPAT_POP_PBB, 4} } ; +#define N_ACTIONS (sizeof(actions) / sizeof(struct ofl_action_header)) + /* When inserting an entry, this function adds the flow entry to the list of * hard and idle timeout entries, if appropriate. */ static void @@ -307,7 +316,7 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp int i; oxm_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); oxm_capabilities->header.type = type; - oxm_capabilities->oxm_num = NUM_OXM_FIELDS; + oxm_capabilities->oxm_num = NUM_OXM_IDS; oxm_capabilities->oxm_ids = oxm_ids; oxm_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&oxm_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) oxm_capabilities; @@ -317,7 +326,7 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp struct ofl_table_feature_prop_oxm *oxm_capabilities; oxm_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); oxm_capabilities->header.type = type; - oxm_capabilities->oxm_num = N_WILDCARDED; + oxm_capabilities->oxm_num = NUM_WILD_IDS; oxm_capabilities->oxm_ids = wildcarded; oxm_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&oxm_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) oxm_capabilities; diff --git a/udatapath/flow_table.h b/udatapath/flow_table.h index b1b1f220..a3b7ead9 100644 --- a/udatapath/flow_table.h +++ b/udatapath/flow_table.h @@ -39,11 +39,7 @@ #define FLOW_TABLE_MAX_ENTRIES 4096 #define TABLE_FEATURES_NUM 14 -// EEDJAS: N_OXM_FIELDS is an enum value exported by oxm-match.h via ofl-structs.h -// #define N_OXM_FIELDS 40 -#define N_INSTRUCTIONS 6 -#define N_ACTIONS 16 -#define N_WILDCARDED 16 + /**************************************************************************** * Implementation of a flow table. The current implementation stores flow * entries in priority and then insertion order. From 6efaac960a0bc4d4f7ceae49748da6caea292769 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 7 Jul 2014 14:38:34 -0700 Subject: [PATCH 034/191] Parse the match for flow-mod deletes with match, fix crash in dpctl. --- utilities/dpctl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index a0418235..74e6f57d 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -617,9 +617,10 @@ flow_mod(struct vconn *vconn, int argc, char *argv[]) { parse_match(argv[1], &(msg.match)); } else { - if(msg.command == OFPFC_DELETE) + if(msg.command == OFPFC_DELETE) { inst_num = 0; - else { + parse_match(argv[1], &(msg.match)); + } else { /*We copy the value because we don't know if it is an instruction or match. If the match is empty, the argv is modified From b8e6a5592ce9d1dfb6dcab5168b8e159fc436828 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Wed, 20 Feb 2013 18:10:12 -0800 Subject: [PATCH 035/191] EXT-258: Implement port liveness, as clarified by EXT-258 --- udatapath/dp_ports.c | 15 +++++++++++++++ udatapath/dp_ports.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/udatapath/dp_ports.c b/udatapath/dp_ports.c index 00c99783..9609f9f8 100644 --- a/udatapath/dp_ports.c +++ b/udatapath/dp_ports.c @@ -408,6 +408,7 @@ new_port(struct datapath *dp, struct sw_port *port, uint32_t port_no, / * FIXME: Add current, supported and advertised features * / #endif } + dp_port_live_update(port); port->stats = xmalloc(sizeof(struct ofl_port_stats)); port->stats->port_no = port_no; @@ -686,6 +687,7 @@ dp_ports_handle_port_mod(struct datapath *dp, struct ofl_msg_port_mod *msg, if (msg->mask) { p->conf->config &= ~msg->mask; p->conf->config |= msg->config & msg->mask; + dp_port_live_update(p); } /*Notify all controllers that the port status has changed*/ @@ -705,6 +707,19 @@ dp_port_stats_update(struct sw_port *port) { port->stats->duration_nsec = ((time_msec() - port->created) % 1000) * 1000; } +void +dp_port_live_update(struct sw_port *p) { + + if((p->conf->state & OFPPS_LINK_DOWN) + || (p->conf->config & OFPPC_PORT_DOWN)) { + /* Port not live */ + p->conf->state &= ~OFPPS_LIVE; + } else { + /* Port is live */ + p->conf->state |= OFPPS_LIVE; + } +} + ofl_err dp_ports_handle_stats_request_port(struct datapath *dp, struct ofl_msg_multipart_request_port *msg, diff --git a/udatapath/dp_ports.h b/udatapath/dp_ports.h index cea9dab6..6ae98347 100644 --- a/udatapath/dp_ports.h +++ b/udatapath/dp_ports.h @@ -149,6 +149,10 @@ ofl_err dp_ports_handle_port_mod(struct datapath *dp, struct ofl_msg_port_mod *msg, const struct sender *sender); +/* Update Live flag on a port/ */ +void +dp_port_live_update(struct sw_port *port); + /* Handles a port stats request message. */ ofl_err dp_ports_handle_stats_request_port(struct datapath *dp, From 074128dfac8d8b875ce351a660f17bb88184f1b5 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Wed, 6 Mar 2013 17:17:59 -0800 Subject: [PATCH 036/191] Implement multipart requests for setting table features. --- oflib/ofl-messages.c | 88 ++++++++++++++++++ udatapath/datapath.c | 5 ++ udatapath/datapath.h | 4 + udatapath/pipeline.c | 87 +++++++++++++++++- utilities/dpctl.c | 206 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 389 insertions(+), 1 deletion(-) diff --git a/oflib/ofl-messages.c b/oflib/ofl-messages.c index 73a2134a..d2c0f381 100644 --- a/oflib/ofl-messages.c +++ b/oflib/ofl-messages.c @@ -360,6 +360,94 @@ ofl_msg_free_flow_removed(struct ofl_msg_flow_removed *msg, bool with_stats, str +bool +ofl_msg_merge_multipart_request_table_features(struct ofl_msg_multipart_request_table_features *orig, struct ofl_msg_multipart_request_table_features *merge) { + uint32_t new_tables_num; + size_t i, j; + struct ofl_table_feature_prop_header **properties; + struct ofl_table_feature_prop_header *old_prop; + struct ofl_table_feature_prop_header *new_prop; + int properties_num; + int k; + + /* Keep body potentially empty if nothing to merge. Jean II */ + if(merge->tables_num) { + new_tables_num = orig->tables_num + merge->tables_num; + + orig->table_features = (struct ofl_table_features ** )realloc(orig->table_features, new_tables_num * sizeof(struct ofl_table_features *)); + + for (i=0; i < merge->tables_num; i++) { + j = orig->tables_num + i; + orig->table_features[j] = (struct ofl_table_features *)malloc(sizeof(struct ofl_table_features)); + memcpy(orig->table_features[j], merge->table_features[i], sizeof(struct ofl_table_features)); + properties = merge->table_features[i]->properties; + properties_num = merge->table_features[i]->properties_num; + for (k = 0; k < properties_num; k++) { + old_prop = properties[k]; + switch (old_prop->type) { + case OFPTFPT_INSTRUCTIONS: + case OFPTFPT_INSTRUCTIONS_MISS: { + struct ofl_table_feature_prop_instructions *old_prop_i = (struct ofl_table_feature_prop_instructions*) old_prop; + struct ofl_table_feature_prop_instructions *new_prop_i; + new_prop_i = (struct ofl_table_feature_prop_instructions*) malloc(sizeof(struct ofl_table_feature_prop_instructions)); + new_prop = (struct ofl_table_feature_prop_header *) new_prop_i; + memcpy((char *) new_prop, (char *) old_prop, sizeof(struct ofl_table_feature_prop_instructions)); + new_prop_i->instruction_ids = (struct ofl_instruction_header*) malloc(sizeof(struct ofl_instruction_header) * old_prop_i->ids_num); + memcpy((char *) new_prop_i->instruction_ids, (char *) old_prop_i->instruction_ids, sizeof(struct ofl_instruction_header) * old_prop_i->ids_num); + break; + } + case OFPTFPT_NEXT_TABLES: + case OFPTFPT_NEXT_TABLES_MISS: { + struct ofl_table_feature_prop_next_tables *old_prop_nt = (struct ofl_table_feature_prop_next_tables*) old_prop; + struct ofl_table_feature_prop_next_tables *new_prop_nt; + new_prop_nt = (struct ofl_table_feature_prop_next_tables*) malloc(sizeof(struct ofl_table_feature_prop_next_tables)); + new_prop = (struct ofl_table_feature_prop_header *) new_prop_nt; + memcpy((char *) new_prop, (char *) old_prop, sizeof(struct ofl_table_feature_prop_next_tables)); + new_prop_nt->next_table_ids = (uint8_t*) malloc(sizeof(uint8_t) * old_prop_nt->table_num); + memcpy((char *) new_prop_nt->next_table_ids, (char *) old_prop_nt->next_table_ids, sizeof(uint8_t) * old_prop_nt->table_num); + break; + } + case OFPTFPT_WRITE_ACTIONS: + case OFPTFPT_WRITE_ACTIONS_MISS: + case OFPTFPT_APPLY_ACTIONS: + case OFPTFPT_APPLY_ACTIONS_MISS: { + struct ofl_table_feature_prop_actions *old_prop_a = (struct ofl_table_feature_prop_actions*) old_prop; + struct ofl_table_feature_prop_actions *new_prop_a; + new_prop_a = (struct ofl_table_feature_prop_actions*) malloc(sizeof(struct ofl_table_feature_prop_actions)); + new_prop = (struct ofl_table_feature_prop_header *) new_prop_a; + memcpy((char *) new_prop, (char *) old_prop, sizeof(struct ofl_table_feature_prop_actions)); + new_prop_a->action_ids = (struct ofl_action_header*) malloc(sizeof(struct ofl_action_header) * old_prop_a->actions_num); + memcpy((char *) new_prop_a->action_ids, (char *) old_prop_a->action_ids, sizeof(struct ofl_action_header) * old_prop_a->actions_num); + break; + } + case OFPTFPT_MATCH: + case OFPTFPT_WILDCARDS: + case OFPTFPT_WRITE_SETFIELD: + case OFPTFPT_WRITE_SETFIELD_MISS: + case OFPTFPT_APPLY_SETFIELD: + case OFPTFPT_APPLY_SETFIELD_MISS: { + struct ofl_table_feature_prop_oxm *old_prop_o = (struct ofl_table_feature_prop_oxm*) old_prop; + struct ofl_table_feature_prop_oxm *new_prop_o; + new_prop_o = (struct ofl_table_feature_prop_oxm*) malloc(sizeof(struct ofl_table_feature_prop_oxm)); + new_prop = (struct ofl_table_feature_prop_header *) new_prop_o; + memcpy((char *) new_prop, (char *) old_prop, sizeof(struct ofl_table_feature_prop_oxm)); + new_prop_o->oxm_ids = (uint32_t*) malloc(sizeof(uint32_t) * old_prop_o->oxm_num); + memcpy((char *) new_prop_o->oxm_ids, (char *) old_prop_o->oxm_ids, sizeof(uint32_t) * old_prop_o->oxm_num); + break; + } + default: + new_prop = NULL; + } + orig->table_features[j]->properties[k] = new_prop; + } + } + + orig->tables_num = new_tables_num; + } + + return ((merge->header.flags & OFPMPF_REQ_MORE) == 0); +} + bool ofl_msg_merge_multipart_reply_flow(struct ofl_msg_multipart_reply_flow *orig, struct ofl_msg_multipart_reply_flow *merge) { uint32_t new_stats_num; diff --git a/udatapath/datapath.c b/udatapath/datapath.c index c8a46ac5..96503a46 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -337,6 +337,9 @@ remote_destroy(struct remote *r) rconn_destroy(r->rconn_aux); } rconn_destroy(r->rconn); + if(r->mp_req_msg != NULL) { + ofl_msg_free((struct ofl_msg_header *) r->mp_req_msg, NULL); + } free(r); } } @@ -351,6 +354,8 @@ remote_create(struct datapath *dp, struct rconn *rconn, struct rconn *rconn_aux) remote->rconn_aux = rconn_aux; remote->cb_dump = NULL; remote->n_txq = 0; + remote->mp_req_msg = NULL; + remote->mp_req_xid = 0; /* Currently not needed. Jean II. */ remote->role = OFPCR_ROLE_EQUAL; /* Set the remote configuration to receive any asynchronous message*/ for(i = 0; i < 2; i++){ diff --git a/udatapath/datapath.h b/udatapath/datapath.h index c0ea3e51..f845bd36 100644 --- a/udatapath/datapath.h +++ b/udatapath/datapath.h @@ -146,6 +146,10 @@ struct remote { uint32_t role; /*OpenFlow controller role.*/ struct ofl_async_config config; /* Asynchronous messages configuration, set from controller*/ + + /* Multipart request message pending reassembly. */ + struct ofl_msg_multipart_request_header *mp_req_msg; /* Message. */ + uint32_t mp_req_xid; /* Multipart request OpenFlow transaction ID. */ }; /* Creates a new datapath */ diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index 8327c844..e3cf6b11 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -373,17 +373,102 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, struct ofl_msg_multipart_request_table_features *feat = (struct ofl_msg_multipart_request_table_features *) msg; - /*Check to see if the body is empty*/ + /* Check if we already received fragments of a multipart request. */ + if(sender->remote->mp_req_msg != NULL) { + bool nomore; + + /* We can only merge requests having the same XID. */ + if(sender->xid != sender->remote->mp_req_xid) + { + VLOG_ERR(LOG_MODULE, "multipart request: wrong xid (0x%X != 0x%X)", sender->xid, sender->remote->mp_req_xid); + + /* Technically, as our buffer can only hold one pending request, + * this is a buffer overflow ! Jean II */ + /* Return error. */ + return ofl_error(OFPET_BAD_REQUEST, OFPBRC_MULTIPART_BUFFER_OVERFLOW); + } + + VLOG_DBG(LOG_MODULE, "multipart request: merging with previous fragments (%d+%d)", ((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg)->tables_num, feat->tables_num); + + /* Merge the request with previous fragments. */ + nomore = ofl_msg_merge_multipart_request_table_features((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg, feat); + + /* Check if incomplete. */ + if(!nomore) + return 0; + + VLOG_DBG(LOG_MODULE, "multipart request: reassembly complete (%d)", ((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg)->tables_num); + + /* Use the complete request. */ + feat = (struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg; + +#if 0 + { + char *str; + str = ofl_msg_to_string((struct ofl_msg_header *) feat, pl->dp->exp); + VLOG_DBG(LOG_MODULE, "\nMerged request:\n%s\n\n", str); + free(str); + } +#endif + + } else { + /* Check if the request is an initial fragment. */ + if(msg->flags & OFPMPF_REQ_MORE) { + struct ofl_msg_multipart_request_table_features* saved_msg; + + VLOG_DBG(LOG_MODULE, "multipart request: create reassembly buffer (%d)", feat->tables_num); + + /* Create a buffer the do reassembly. */ + saved_msg = (struct ofl_msg_multipart_request_table_features*) malloc(sizeof(struct ofl_msg_multipart_request_table_features)); + saved_msg->header.header.type = OFPT_MULTIPART_REQUEST; + saved_msg->header.type = OFPMP_TABLE_FEATURES; + saved_msg->header.flags = 0; + saved_msg->tables_num = 0; + saved_msg->table_features = NULL; + + /* Save the fragment for later use. */ + ofl_msg_merge_multipart_request_table_features(saved_msg, feat); + sender->remote->mp_req_msg = (struct ofl_msg_multipart_request_header *) saved_msg; + sender->remote->mp_req_xid = sender->xid; + + return 0; + } + + /* Non fragmented request. Nothing to do... */ + VLOG_DBG(LOG_MODULE, "multipart request: non-fragmented request (%d)", feat->tables_num); + } + + /*Check to see if the body is empty.*/ + /* Should check merge->tables_num instead. Jean II */ if(feat->table_features != NULL){ /* Change tables configuration TODO: Remove flows*/ + /* TODO : In theory, tables missing from the request should be + * disabled ! Maybe we could return an error if table number not + * the same, like OFPTFFC_BAD_TABLE... Jean II */ + VLOG_DBG(LOG_MODULE, "pipeline_handle_stats_request_table_features_request: updating features"); for(i = 0; i < feat->tables_num; i++){ + /* Obvious memory leak. + * Obvious memory ownership issue when non-frag requests. + * Jean II */ pl->tables[feat->table_features[i]->table_id]->features = feat->table_features[i]; } } + /* Cleanup request. */ + if(sender->remote->mp_req_msg != NULL) { + /* Can't free entire structure, we are pointing to it ! */ + //ofl_msg_free((struct ofl_msg_header *) sender->remote->mp_req_msg, NULL); + free(sender->remote->mp_req_msg); + sender->remote->mp_req_msg = NULL; + sender->remote->mp_req_xid = 0; /* Currently not needed. Jean II. */ + } + j = 0; /* Query for table capabilities */ + /* Note : PIPELINE_TABLES must be multiple of 8 for this code to work. + * Otherwise we go out of bounds and may not set the MORE flags properly. + * Jean II */ loop: ; features = (struct ofl_table_features**) xmalloc(sizeof(struct ofl_table_features *) * 8); for (i = 0; i < 8; i++){ diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 74e6f57d..39db5d80 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -186,6 +186,9 @@ parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32 static int parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val, uint32_t **mask); +static void +set_table_features_match(struct vconn *vconn, int argc, char *argv[]); + static struct ofl_exp_msg dpctl_exp_msg = {.pack = ofl_exp_msg_pack, .unpack = ofl_exp_msg_unpack, @@ -924,6 +927,7 @@ static struct command all_commands[] = { {"table-mod", 1, 1, table_mod }, {"queue-get-config", 1, 1, queue_get_config}, {"set-desc", 1, 1, set_desc}, + {"set-table-match", 0, 2, set_table_features_match}, {"queue-mod", 3, 3, queue_mod}, {"queue-del", 2, 2, queue_del} @@ -2694,3 +2698,205 @@ parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint3 } return 0; } + +struct oxm_str_mapping { + char * name; + uint32_t oxm_id; +}; +struct oxm_str_mapping oxm_str_map[] = + { { .name=MATCH_IN_PORT, .oxm_id=OXM_OF_IN_PORT }, + { .name=MATCH_DL_SRC, .oxm_id=OXM_OF_ETH_SRC }, + { .name=MATCH_DL_DST, .oxm_id=OXM_OF_ETH_DST }, + { .name=MATCH_ARP_SHA, .oxm_id=OXM_OF_ARP_SHA }, + { .name=MATCH_ARP_THA, .oxm_id=OXM_OF_ARP_THA }, + { .name=MATCH_ARP_SPA, .oxm_id=OXM_OF_ARP_SPA }, + { .name=MATCH_ARP_TPA, .oxm_id=OXM_OF_ARP_TPA }, + { .name=MATCH_ARP_OP, .oxm_id=OXM_OF_ARP_OP }, + { .name=MATCH_DL_VLAN, .oxm_id=OXM_OF_VLAN_VID }, + { .name=MATCH_DL_VLAN_PCP, .oxm_id=OXM_OF_VLAN_PCP }, + { .name=MATCH_DL_TYPE, .oxm_id=OXM_OF_ETH_TYPE }, + { .name=MATCH_IP_ECN, .oxm_id=OXM_OF_IP_ECN }, + { .name=MATCH_IP_DSCP, .oxm_id=OXM_OF_IP_DSCP }, + { .name=MATCH_NW_PROTO, .oxm_id=OXM_OF_IP_PROTO }, + { .name=MATCH_NW_SRC, .oxm_id=OXM_OF_IPV4_SRC }, + { .name=MATCH_NW_DST, .oxm_id=OXM_OF_IPV4_DST }, + { .name=MATCH_ICMPV4_CODE, .oxm_id=OXM_OF_ICMPV4_CODE }, + { .name=MATCH_ICMPV4_TYPE, .oxm_id=OXM_OF_ICMPV4_TYPE }, + { .name=MATCH_TP_SRC, .oxm_id=OXM_OF_TCP_SRC }, + { .name=MATCH_TP_DST, .oxm_id=OXM_OF_TCP_DST }, + { .name=MATCH_UDP_SRC, .oxm_id=OXM_OF_UDP_SRC }, + { .name=MATCH_UDP_DST, .oxm_id=OXM_OF_UDP_DST }, + { .name=MATCH_SCTP_SRC, .oxm_id=OXM_OF_SCTP_SRC }, + { .name=MATCH_SCTP_DST, .oxm_id=OXM_OF_SCTP_DST }, + { .name=MATCH_MPLS_LABEL, .oxm_id=OXM_OF_MPLS_LABEL }, + { .name=MATCH_MPLS_TC, .oxm_id=OXM_OF_MPLS_TC }, + { .name=MATCH_MPLS_BOS, .oxm_id=OXM_OF_MPLS_BOS }, + { .name=MATCH_NW_SRC_IPV6, .oxm_id=OXM_OF_IPV6_SRC }, + { .name=MATCH_NW_DST_IPV6, .oxm_id=OXM_OF_IPV6_DST }, + { .name=MATCH_IPV6_FLABEL, .oxm_id=OXM_OF_IPV6_FLABEL }, + { .name=MATCH_ICMPV6_CODE, .oxm_id=OXM_OF_ICMPV6_CODE }, + { .name=MATCH_ICMPV6_TYPE, .oxm_id=OXM_OF_ICMPV6_TYPE }, + { .name=MATCH_IPV6_ND_TARGET, .oxm_id=OXM_OF_IPV6_ND_TARGET }, + { .name=MATCH_IPV6_ND_SLL, .oxm_id=OXM_OF_IPV6_ND_SLL }, + { .name=MATCH_IPV6_ND_TLL, .oxm_id=OXM_OF_IPV6_ND_TLL }, + { .name=MATCH_METADATA, .oxm_id=OXM_OF_METADATA }, + { .name=MATCH_PBB_ISID, .oxm_id=OXM_OF_PBB_ISID }, + { .name=MATCH_TUNNEL_ID, .oxm_id=OXM_OF_TUNNEL_ID }, + { .name=MATCH_EXT_HDR, .oxm_id=OXM_OF_IPV6_EXTHDR }, + }; + +static void +parse_feature_prop_match(char *str, struct ofl_table_feature_prop_oxm **prop_addr) { + char *token, *saveptr = NULL; + const int oxm_max = sizeof(oxm_str_map) / sizeof(oxm_str_map[0]); + uint32_t *oxm_array = (uint32_t *) xmalloc(sizeof(uint32_t) * 80); + struct ofl_table_feature_prop_oxm *property; + int oxm_num = 0; + int id; + + for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { + if (strncmp(token, "apply", strlen("apply")) == 0 || strncmp(token, "write", strlen("write")) == 0 ) { + break; + } + if (oxm_num >= oxm_max) { + break; + } + for (id = 0; id < oxm_max; id++) { + + if (strncmp(token, oxm_str_map[id].name, strlen(oxm_str_map[id].name)) == 0) { + oxm_array[oxm_num++] = oxm_str_map[id].oxm_id; + break; + } + } + } + + property = (struct ofl_table_feature_prop_oxm *) xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); + property->header.type = OFPTFPT_MATCH; + property->header.length = (sizeof(struct ofp_table_feature_prop_oxm) + oxm_num * sizeof(uint32_t)); + property->oxm_num = oxm_num; + property->oxm_ids = oxm_array; + (*prop_addr) = property; +} + +static void +set_table_features_match(struct vconn *vconn, int argc, char *argv[]) { + struct ofl_msg_multipart_request_table_features req_init = + {{{.type = OFPT_MULTIPART_REQUEST}, + .type = OFPMP_TABLE_FEATURES, .flags = 0x0000}, + .tables_num = 0, + .table_features = NULL, + }; + struct ofl_msg_header *reply; + struct ofl_msg_multipart_request_table_features *table_feat; + int t; + int last_table; + int batch_table; + + /* Extract current table features */ + dpctl_transact(vconn, (struct ofl_msg_header *)&req_init, &reply); + table_feat = (struct ofl_msg_multipart_request_table_features *) reply; + + if (argc > 0) { + struct ofl_table_feature_prop_oxm *new_match; + struct ofl_table_feature_prop_header **properties; + int properties_num; + int i; + + /* New match features */ + parse_feature_prop_match(argv[0], &new_match); + { + char *str; + str = ofl_structs_table_properties_to_string((struct ofl_table_feature_prop_header *) new_match); + printf("New match property:%s\n\n", str); + free(str); + } + + /* Set them in all the table features */ + for(t = 0; t < table_feat->tables_num; t++) { + properties = table_feat->table_features[t]->properties; + properties_num = table_feat->table_features[t]->properties_num; + for (i = 0; i < properties_num; i++) { + if(properties[i]->type == OFPTFPT_MATCH) { + struct ofl_table_feature_prop_oxm *clone_match; + clone_match = (struct ofl_table_feature_prop_oxm *) xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); + memcpy((char *) clone_match, (char *) new_match, sizeof(struct ofl_table_feature_prop_oxm)); + clone_match->oxm_ids = (uint32_t *) xmalloc(clone_match->oxm_num * sizeof(uint32_t)); + memcpy((char *) clone_match->oxm_ids, new_match->oxm_ids, clone_match->oxm_num * sizeof(uint32_t)); + + ofl_structs_free_table_properties(properties[i], &dpctl_exp); + properties[i] = (struct ofl_table_feature_prop_header *) clone_match; + } + } + } + + ofl_structs_free_table_properties((struct ofl_table_feature_prop_header *) new_match, &dpctl_exp); + + } + + { + int features_len; + printf("\nJII table-num:%d\n", table_feat->tables_num); + features_len = ofl_structs_table_features_ofp_total_len(table_feat->table_features, table_feat->tables_num, NULL); + printf("\nJII features_len:%d\n", features_len); + } + + /* Turn the reply into a request */ + table_feat->header.header.type = OFPT_MULTIPART_REQUEST; + + /* Renumber tables to form multipart request */ + last_table = table_feat->table_features[table_feat->tables_num - 1]->table_id; + t = 0; + batch_table = table_feat->tables_num; + while(t < last_table) { + int i; + int prev_t = t; + for(i = 0; i < batch_table; i++) { + table_feat->table_features[i]->table_id = t; + table_feat->table_features[i]->name[0] = '\0'; + t++; + if(t > last_table) + break; + } + + /* Set the request parameters. */ + table_feat->tables_num = t - prev_t; + +#if 0 + { + char *str; + str = ofl_msg_to_string(reply, &dpctl_exp); + printf("\nNew table request (t=%d/%d, num=%d):\n%s\n\n", t, last_table, table_feat->tables_num, str); + free(str); + } +#endif + + /* Intermediate and last segment are not treated the same. Jean II */ + if(t <= last_table) { + struct ofpbuf *ofpbufreq, *ofpbufrepl; + uint8_t *bufreq; + size_t bufreq_size; + int error; + + table_feat->header.flags = OFPMPF_REQ_MORE; + + error = ofl_msg_pack((struct ofl_msg_header *)table_feat, XID, &bufreq, &bufreq_size, NULL); + if (error) { + ofp_fatal(0, "Error packing request."); + } + printf("\nJII-req-pack:%d\n", bufreq_size); + + ofpbufreq = ofpbuf_new(0); + ofpbuf_use(ofpbufreq, bufreq, bufreq_size); + ofpbuf_put_uninit(ofpbufreq, bufreq_size); + error = vconn_send_block(vconn, ofpbufreq); + if (error) { + ofp_fatal(0, "Error during transaction."); + } + /* No reply. */ + } else { + table_feat->header.flags = 0; + + dpctl_transact_and_print(vconn, (struct ofl_msg_header *)table_feat, NULL); + } + } +} From 81028e90512b93e5602f85fbaeab4272e787b3a8 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Thu, 7 Mar 2013 18:26:13 -0800 Subject: [PATCH 037/191] Handle case of setting features for 8+1 tables --- utilities/dpctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 39db5d80..d63a7f58 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -2847,7 +2847,7 @@ set_table_features_match(struct vconn *vconn, int argc, char *argv[]) { last_table = table_feat->table_features[table_feat->tables_num - 1]->table_id; t = 0; batch_table = table_feat->tables_num; - while(t < last_table) { + while(t <= last_table) { int i; int prev_t = t; for(i = 0; i < batch_table; i++) { From 4e414f8ba80f3607e1f43637a6058b5106866935 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 11 Mar 2013 10:16:00 -0700 Subject: [PATCH 038/191] Framework to enable and disable tables. --- udatapath/flow_table.c | 1 + udatapath/flow_table.h | 1 + udatapath/pipeline.c | 30 +++++++++++++++++++++--------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/udatapath/flow_table.c b/udatapath/flow_table.c index 415c3399..c3cfec18 100644 --- a/udatapath/flow_table.c +++ b/udatapath/flow_table.c @@ -370,6 +370,7 @@ flow_table_create(struct datapath *dp, uint8_t table_id) { table = xmalloc(sizeof(struct flow_table)); table->dp = dp; + table->disabled = 0; /*Init table stats */ table->stats = xmalloc(sizeof(struct ofl_table_stats)); diff --git a/udatapath/flow_table.h b/udatapath/flow_table.h index a3b7ead9..9ee45635 100644 --- a/udatapath/flow_table.h +++ b/udatapath/flow_table.h @@ -48,6 +48,7 @@ struct flow_table { struct datapath *dp; + bool disabled; /* Don't use that table. */ struct ofl_table_features *features; /*store table features*/ struct ofl_table_stats *stats; /* structure storing table statistics. */ diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index e3cf6b11..2cda4a0c 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -441,17 +441,22 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, /*Check to see if the body is empty.*/ /* Should check merge->tables_num instead. Jean II */ if(feat->table_features != NULL){ + /* Disable all tables, they will be selectively re-enabled. */ + for(i = 0; i < PIPELINE_TABLES; i++){ + pl->tables[i]->disabled = true; + } /* Change tables configuration TODO: Remove flows*/ - /* TODO : In theory, tables missing from the request should be - * disabled ! Maybe we could return an error if table number not - * the same, like OFPTFFC_BAD_TABLE... Jean II */ + /* TODO : In theory, tables should be in ascending order ! + * Maybe we could return an error if table number not + * expected, like OFPTFFC_BAD_TABLE... Jean II */ VLOG_DBG(LOG_MODULE, "pipeline_handle_stats_request_table_features_request: updating features"); for(i = 0; i < feat->tables_num; i++){ /* Obvious memory leak. * Obvious memory ownership issue when non-frag requests. * Jean II */ pl->tables[feat->table_features[i]->table_id]->features = feat->table_features[i]; + pl->tables[i]->disabled = false; } } @@ -466,21 +471,28 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, j = 0; /* Query for table capabilities */ - /* Note : PIPELINE_TABLES must be multiple of 8 for this code to work. - * Otherwise we go out of bounds and may not set the MORE flags properly. - * Jean II */ loop: ; features = (struct ofl_table_features**) xmalloc(sizeof(struct ofl_table_features *) * 8); + /* Return 8 tables per reply segment. */ for (i = 0; i < 8; i++){ + /* Skip disabled tables. */ + while((j < PIPELINE_TABLES) && (pl->tables[j]->disabled == true)) + j++; + /* Stop at the last table. */ + if(j >= PIPELINE_TABLES) + break; + /* Use that table in the reply. */ features[i] = pl->tables[j]->features; j++; } + VLOG_DBG(LOG_MODULE, "multipart reply: returning %d tables, next table-id %d", i, j); { struct ofl_msg_multipart_reply_table_features reply = - {{{.type = OFPT_MULTIPART_REPLY}, - .type = OFPMP_TABLE_FEATURES, .flags = j == PIPELINE_TABLES? 0x00000000:OFPMPF_REPLY_MORE}, + {{{.type = OFPT_MULTIPART_REPLY}, + .type = OFPMP_TABLE_FEATURES, + .flags = (j == PIPELINE_TABLES ? 0x00000000 : OFPMPF_REPLY_MORE) }, .table_features = features, - .tables_num = 8}; + .tables_num = i }; dp_send_message(pl->dp, (struct ofl_msg_header *)&reply, sender); } if (j < PIPELINE_TABLES){ From 2836522c1fdd2d5a0b759935c8b914abf41af441 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Thu, 7 Mar 2013 18:23:20 -0800 Subject: [PATCH 039/191] Validate table ids in feature requests and generate error. --- udatapath/pipeline.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index 2cda4a0c..8478e525 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -373,6 +373,17 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, struct ofl_msg_multipart_request_table_features *feat = (struct ofl_msg_multipart_request_table_features *) msg; + /* Further validation of request not done in + * ofl_structs_table_features_unpack(). Jean II */ + if(feat->table_features != NULL) { + for(i = 0; i < feat->tables_num; i++){ + if(feat->table_features[i]->table_id >= PIPELINE_TABLES) + return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_TABLE); + /* We may want to validate things like config, max_entries, + * metadata... */ + } + } + /* Check if we already received fragments of a multipart request. */ if(sender->remote->mp_req_msg != NULL) { bool nomore; From 786455f1619fe074705bb7d77340d95e25308991 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 18 Mar 2013 15:44:47 -0700 Subject: [PATCH 040/191] Role status events (from Dingwanfu - Huawei). --- include/openflow/openflow.h | 58 +++++++++++++++++++++++++++++++++++++ oflib/ofl-messages-pack.c | 25 +++++++++++++++- oflib/ofl-messages-print.c | 15 +++++++++- oflib/ofl-messages-unpack.c | 24 +++++++++++++++ oflib/ofl-messages.h | 10 +++++++ udatapath/datapath.c | 15 ++++++++++ 6 files changed, 145 insertions(+), 2 deletions(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index caa4e840..951159aa 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -93,6 +93,9 @@ enum ofp_type { OFPT_SET_ASYNC = 28, /* Controller/switch message */ /* Meters and rate limiters configuration messages. */ OFPT_METER_MOD = 29, /* Controller/switch message */ + + /*modified by dingwanfu*/ + OFPT_ROLE_STATUS =30, /* Async message */ }; /* OFPT_HELLO. This message has an empty body, but implementations must @@ -1492,6 +1495,44 @@ struct ofp_error_msg { }; OFP_ASSERT(sizeof(struct ofp_error_msg) == 12); +/*modified by dingwanfu*/ +/* Common header for Role Properties */ +struct ofp_role_prop_header { + uint16_t type; /* One of OFPRPT_*. */ + uint16_t length; /* Length in bytes of the properity. */ +}; +OFP_ASSERT(sizeof(struct ofp_role_prop_header) ==4); + +/*modified by dingwanfu*/ +/* Experimenter role property */ +struct ofp_role_prop_expermenter { + uint16_t type; + uint16_t length; + uint32_t experimenter; + uint32_t exp_type; + /* Followed by : + * -Exactly (length -12) bytes containing the experimenter data, then + * -Exactly (length + 7)/8*8 - (length) (between 0 - 7) bytes of all-zero bytes */ + + uint32_t experimenter_data[0]; +}; +OFP_ASSERT(sizeof(struct ofp_role_prop_expermenter) ==12); +D +/*modified by dingwanfu*/ +/* Role status event message. */ +struct ofp_role_status { + struct ofp_header header; /* Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. */ + uint32_t role; /* One of OFPCR_ROLE_*. */ + uint8_t reason; /* One of OFPCR_*. */ + uint8_t pad[3]; /* Align to 64 bits. */ + uint64_t generation_id; /* Master Election Generation Id */ + + /* Role Property list */ + struct ofp_role_prop_header properties[0]; +}; +OFP_ASSERT(sizeof(struct ofp_role_status) == 24); + + /* 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). */ @@ -1728,6 +1769,23 @@ enum ofp_table_features_failed_code { OFPTFFC_EPERM = 5, /* Permissions error. */ }; + +/*modified by dingwanfu*/ +/* What changed about controller role */ +enum ofp_controller_role_reason { + OFPCRR_MASTER_REQUEST = 0, /* Another controller asked to be master. */ + OFPCRR_CONFIG = 1, /* Configuration changed on the switch. */ + OFPCRR_EXPERIMENTER = 2, /* Experimenter data changed. */ +}; + + +/*modified by dingwanfu*/ +/* Role property types. */ +enum ofp_role_prop_type { + OFPCRT_EXPERIMENTER = 0xFFFF, /* Experimenter property. */ +}; + + /* OFPET_EXPERIMENTER: Error message (datapath -> controller). */ struct ofp_error_experimenter_msg { struct ofp_header header; diff --git a/oflib/ofl-messages-pack.c b/oflib/ofl-messages-pack.c index 234f865e..36329dd7 100644 --- a/oflib/ofl-messages-pack.c +++ b/oflib/ofl-messages-pack.c @@ -93,6 +93,23 @@ ofl_msg_pack_role_request(struct ofl_msg_role_request *msg, uint8_t **buf, size_ return 0; } +/*modified by dingwanfu*/ +static int +ofl_msg_pack_role_status(struct ofl_msg_role_status *msg, uint8_t **buf, size_t *buf_len) { + struct ofp_role_status *sta; + *buf_len = sizeof(struct ofp_role_status); + *buf = (uint8_t *)malloc(*buf_len); + + sta = (struct ofl_msg_role_status *)(*buf); + sta->role = htonl(msg->role); + sta->reason = msg->reason; + memset(sta->pad,0,sizeof(sta->pad)); + sta->generation_id = hton64(msg->generation_id); + + return 0; +} + + static int ofl_msg_pack_features_reply(struct ofl_msg_features_reply *msg, uint8_t **buf, size_t *buf_len) { struct ofp_switch_features *features; @@ -1105,9 +1122,15 @@ ofl_msg_pack(struct ofl_msg_header *msg, uint32_t xid, uint8_t **buf, size_t *bu break; } case OFPT_ROLE_REQUEST: - case OFPT_ROLE_REPLY: + case OFPT_ROLE_REPLY: { error = ofl_msg_pack_role_request((struct ofl_msg_role_request*)msg, buf, buf_len); + break;/*modified by dignwanfu*/ + } + /*modified by dignwanfu*/ + case OFPT_ROLE_STATUS:{ + error = ofl_msg_pack_role_status((struct ofl_msg_role_status*)msg, buf, buf_len); break; + } default: { OFL_LOG_WARN(LOG_MODULE, "Trying to pack unknown message type."); error = -1; diff --git a/oflib/ofl-messages-print.c b/oflib/ofl-messages-print.c index 24ddcd6c..6afe8aa5 100644 --- a/oflib/ofl-messages-print.c +++ b/oflib/ofl-messages-print.c @@ -679,6 +679,14 @@ ofl_msg_print_role_msg(struct ofl_msg_role_request *msg, FILE *stream){ } +/*modified by dingwanfu*/ +static void +ofl_msg_print_role_stats_msg(struct ofl_msg_role_status *msg, FILE * stream){ + + fprintf(stream, "{role= %d, reason= %d, generation_id= %lld}", msg->role, msg->reason, msg->generation_id); + +} + static void ofl_msg_print_async(struct ofl_msg_async_config* msg, FILE *stream){ @@ -751,6 +759,12 @@ ofl_msg_print(FILE *stream, struct ofl_msg_header *msg, struct ofl_exp *exp) { case OFPT_ROLE_REPLY:{ ofl_msg_print_role_msg((struct ofl_msg_role_request*)msg, stream); } + + /*modified by dingwanfu */ + case OFPT_ROLE_STATUS:{ + ofl_msg_print_role_stats_msg((struct ofl_msg_role_request*)msg, stream); + } + /* Queue Configuration messages. */ case OFPT_QUEUE_GET_CONFIG_REQUEST: { ofl_msg_print_queue_get_config_request((struct ofl_msg_queue_get_config_request *)msg, stream); return; } case OFPT_QUEUE_GET_CONFIG_REPLY: { ofl_msg_print_queue_get_config_reply((struct ofl_msg_queue_get_config_reply *)msg, stream); return; } @@ -759,7 +773,6 @@ ofl_msg_print(FILE *stream, struct ofl_msg_header *msg, struct ofl_exp *exp) { case OFPT_GET_ASYNC_REQUEST:{return;} case OFPT_GET_ASYNC_REPLY: case OFPT_SET_ASYNC:{ofl_msg_print_async((struct ofl_msg_async_config*)msg, stream); return;} - case OFPT_METER_MOD: {ofl_msg_print_meter_mod((struct ofl_msg_meter_mod*)msg, stream); return;} } diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 7c131757..80f53f20 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -114,6 +114,30 @@ ofl_msg_unpack_role_request(struct ofp_header *src, size_t *len, struct ofl_msg_ return 0; } +/*modified by dingwanfu*/ +static int +ofl_msg_unpack_role_status(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + + struct ofp_role_status * srl; + struct ofl_msg_role_status * drl; + + if (*len < sizeof(struct ofp_role_status)){ + OFL_LOG_WARN(LOG_MODULE, "Received ROLE_STATUS message has invalid length (%zu).", *len); + return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + *len -= sizeof(struct ofp_role_status); + + srl = (struct ofp_role_status *) src; + drl = (struct ofl_msg_role_status *) malloc(sizeof(struct ofl_msg_role_status)); + + drl->role = ntohl(srl->role); + drl->reason = srl->reason; + drl->generation_id = ntoh64(srl->generation_id); + + *msg = (struct ofl_msg_header *)drl; + return 0; +} + static ofl_err ofl_msg_unpack_features_reply(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { struct ofp_switch_features *sr; diff --git a/oflib/ofl-messages.h b/oflib/ofl-messages.h index 39770730..ddacdb96 100644 --- a/oflib/ofl-messages.h +++ b/oflib/ofl-messages.h @@ -125,7 +125,17 @@ struct ofl_msg_role_request { uint64_t generation_id; /* Master Election Generation Id */ }; +/*modified by dingwanfu*/ +struct ofl_msg_role_status { + struct ofp_header header; /* Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. */ + uint32_t role; /* One of OFPCR_ROLE_*. */ + uint8_t reason; /* One of OFPCR_*. */ + uint8_t pad[3]; /* Align to 64 bits. */ + uint64_t generation_id; /* Master Election Generation Id */ + /* Role Property list */ + struct ofp_role_prop_header properties[0]; +}; /************************ * Asynchronous messages diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 96503a46..a19dfc3f 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -624,6 +624,21 @@ dp_handle_role_request(struct datapath *dp, struct ofl_msg_role_request *msg, LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { if (r->role == OFPCR_ROLE_MASTER) { r->role = OFPCR_ROLE_SLAVE; + + /*modified by dingwanfu*/ + /* Send ROLE_STATUS message to old master(s) */ + if (r != sender->remote){ /* Do not send message to the request controller */ + struct ofl_msg_role_status status = + {{.type = OFPT_ROLE_STATUS}, + .role = OFPCR_ROLE_SLAVE, + .reason = OFPCRR_MASTER_REQUEST, + .generation_id = msg->generation_id}; + struct sender rsender = { + .remote = r, + .xid = 0}; + dp_send_message(dp, (struct ofl_msg_header *)&status, &rsender); + } + } } sender->remote->role = OFPCR_ROLE_MASTER; From 4918dfaaab6a535298f4b8206826bdaf50142d10 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 18 Mar 2013 16:01:41 -0700 Subject: [PATCH 041/191] Fix typo preventing compile. --- include/openflow/openflow.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 951159aa..1c52618d 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -1517,7 +1517,7 @@ struct ofp_role_prop_expermenter { uint32_t experimenter_data[0]; }; OFP_ASSERT(sizeof(struct ofp_role_prop_expermenter) ==12); -D + /*modified by dingwanfu*/ /* Role status event message. */ struct ofp_role_status { From aa85c03faeb67db28f847184b15f4918459609df Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 18 Mar 2013 16:06:54 -0700 Subject: [PATCH 042/191] Send gratuitous role status message on master loss (from Dingwanfu - Huawei). --- include/openflow/openflow.h | 1 + udatapath/datapath.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 1c52618d..52e8fe4a 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -1776,6 +1776,7 @@ enum ofp_controller_role_reason { OFPCRR_MASTER_REQUEST = 0, /* Another controller asked to be master. */ OFPCRR_CONFIG = 1, /* Configuration changed on the switch. */ OFPCRR_EXPERIMENTER = 2, /* Experimenter data changed. */ + OFPCRR_MASTER_FAIL = 3, /* Master controller connection fail. */ }; diff --git a/udatapath/datapath.c b/udatapath/datapath.c index a19dfc3f..8d0a89aa 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -231,12 +231,40 @@ dp_run(struct datapath *dp) { } } +/*modified by dingwanfu for EXT-276*/ +/* send role_status (MASTER_FAIL) information to remote controllers when master is done*/ +static int +send_role_status_to_remote(struct datapath* dp) +{ + struct remote* r; + + LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { + if (r->role != OFPCR_ROLE_MASTER) { + + /* Send ROLE_STATUS (MASTER_FAIL) message to other controllers */ + struct ofl_msg_role_status status = + {{.type = OFPT_ROLE_STATUS}, + .role = r->role, + .reason = OFPCRR_MASTER_FAIL, + .generation_id = dp->generation_id}; + struct sender rsender = { + .remote = r, + .xid = 0}; + dp_send_message(dp, (struct ofl_msg_header *)&status, &rsender); + } + } + +} + static void remote_run(struct datapath *dp, struct remote *r) { remote_rconn_run(dp, r, MAIN_CONNECTION); if (!rconn_is_alive(r->rconn)) { + /*modified by dingwanfu for EXT-276*/ + if (r->role == OFPCR_ROLE_MASTER) + send_role_status_to_remote(dp); remote_destroy(r); return; } From 385d29c25190495a0f966e6364a8f0f0afeb3141 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 18 Mar 2013 16:10:11 -0700 Subject: [PATCH 043/191] Remove OFPCRR_MASTER_FAIL which is not defined by the spec. --- include/openflow/openflow.h | 1 - udatapath/datapath.c | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 52e8fe4a..1c52618d 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -1776,7 +1776,6 @@ enum ofp_controller_role_reason { OFPCRR_MASTER_REQUEST = 0, /* Another controller asked to be master. */ OFPCRR_CONFIG = 1, /* Configuration changed on the switch. */ OFPCRR_EXPERIMENTER = 2, /* Experimenter data changed. */ - OFPCRR_MASTER_FAIL = 3, /* Master controller connection fail. */ }; diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 8d0a89aa..2dc5917a 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -232,7 +232,7 @@ dp_run(struct datapath *dp) { } /*modified by dingwanfu for EXT-276*/ -/* send role_status (MASTER_FAIL) information to remote controllers when master is done*/ +/* send role_status (OFPCRR_EXPERIMENTER) information to remote controllers when master is done*/ static int send_role_status_to_remote(struct datapath* dp) { @@ -241,11 +241,11 @@ send_role_status_to_remote(struct datapath* dp) LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { if (r->role != OFPCR_ROLE_MASTER) { - /* Send ROLE_STATUS (MASTER_FAIL) message to other controllers */ + /* Send ROLE_STATUS (OFPCRR_EXPERIMENTER) message to other controllers */ struct ofl_msg_role_status status = {{.type = OFPT_ROLE_STATUS}, .role = r->role, - .reason = OFPCRR_MASTER_FAIL, + .reason = OFPCRR_EXPERIMENTER, .generation_id = dp->generation_id}; struct sender rsender = { .remote = r, From 9cc2d36ba0c8740f0f70e23c81e37d7cdc93a9b0 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Mar 2013 16:38:08 -0700 Subject: [PATCH 044/191] Reject goto instruction in the last table. --- udatapath/pipeline.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index 8478e525..f2abec99 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -234,6 +234,10 @@ pipeline_handle_flow_mod(struct pipeline *pl, struct ofl_msg_flow_mod *msg, return error; } } + /* Reject goto in the last table. */ + if ((msg->table_id == (PIPELINE_TABLES - 1)) + && (msg->instructions[i]->type == OFPIT_GOTO_TABLE)) + return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNSUP_INST); } if (msg->table_id == 0xff) { From 7405d77ee1f2815bdcc43ab18c20af5e8765535a Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Mar 2013 16:38:34 -0700 Subject: [PATCH 045/191] When switch has one table, don't advertise goto instruction. --- udatapath/flow_table.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/udatapath/flow_table.c b/udatapath/flow_table.c index c3cfec18..971db7dd 100644 --- a/udatapath/flow_table.c +++ b/udatapath/flow_table.c @@ -68,6 +68,9 @@ uint32_t wildcarded[] = {OXM_OF_METADATA, OXM_OF_ETH_DST, OXM_OF_ETH_SRC, OXM_OF struct ofl_instruction_header instructions[] = { {OFPIT_GOTO_TABLE}, {OFPIT_WRITE_METADATA },{OFPIT_WRITE_ACTIONS},{OFPIT_APPLY_ACTIONS}, {OFPIT_CLEAR_ACTIONS},{OFPIT_METER}} ; +struct ofl_instruction_header instructions_nogoto[] = { + {OFPIT_WRITE_METADATA },{OFPIT_WRITE_ACTIONS},{OFPIT_APPLY_ACTIONS}, + {OFPIT_CLEAR_ACTIONS},{OFPIT_METER}} ; #define N_INSTRUCTIONS (sizeof(instructions) / sizeof(struct ofl_instruction_header)) @@ -274,8 +277,13 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp struct ofl_table_feature_prop_instructions *inst_capabilities; inst_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_instructions)); inst_capabilities->header.type = type; - inst_capabilities->ids_num = N_INSTRUCTIONS; - inst_capabilities->instruction_ids = instructions; + if (PIPELINE_TABLES > 1) { + inst_capabilities->ids_num = N_INSTRUCTIONS; + inst_capabilities->instruction_ids = instructions; + } else { + inst_capabilities->ids_num = N_INSTRUCTIONS - 1; + inst_capabilities->instruction_ids = instructions_nogoto; + } inst_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&inst_capabilities->header, NULL); (*prop) = (struct ofl_table_feature_prop_header*) inst_capabilities; break; From 41e3f82a8225f726dc15ee405400940f821dae95 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 10 Jun 2013 15:10:07 -0700 Subject: [PATCH 046/191] Add ability to set and display XIDs in dpctl --- utilities/dpctl.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index d63a7f58..3b9769dc 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -82,6 +82,7 @@ // response, barrier resp., or the error #define XID 0xf0ff00f0 +static uint32_t global_xid = XID; struct command { char *name; @@ -205,13 +206,13 @@ static struct ofl_exp dpctl_exp = static void dpctl_transact(struct vconn *vconn, struct ofl_msg_header *req, - struct ofl_msg_header **repl) { + struct ofl_msg_header **repl, uint32_t *repl_xid_p) { struct ofpbuf *ofpbufreq, *ofpbufrepl; uint8_t *bufreq; size_t bufreq_size; int error; - error = ofl_msg_pack(req, XID, &bufreq, &bufreq_size, &dpctl_exp); + error = ofl_msg_pack(req, global_xid, &bufreq, &bufreq_size, &dpctl_exp); if (error) { ofp_fatal(0, "Error packing request."); } @@ -223,7 +224,7 @@ dpctl_transact(struct vconn *vconn, struct ofl_msg_header *req, if (error) { ofp_fatal(0, "Error during transaction."); } - error = ofl_msg_unpack(ofpbufrepl->data, ofpbufrepl->size, repl, NULL /*xid_ptr*/, &dpctl_exp); + error = ofl_msg_unpack(ofpbufrepl->data, ofpbufrepl->size, repl, repl_xid_p, &dpctl_exp); if (error) { ofp_fatal(0, "Error unpacking reply."); @@ -241,14 +242,15 @@ static void dpctl_transact_and_print(struct vconn *vconn, struct ofl_msg_header *req, struct ofl_msg_header **repl) { struct ofl_msg_header *reply; + uint32_t repl_xid; char *str; str = ofl_msg_to_string(req, &dpctl_exp); - printf("\nSENDING:\n%s\n\n", str); + printf("\nSENDING (xid=0x%X):\n%s\n\n", global_xid, str); free(str); - dpctl_transact(vconn, req, &reply); + dpctl_transact(vconn, req, &reply, &repl_xid); str = ofl_msg_to_string(reply, &dpctl_exp); - printf("\nRECEIVED:\n%s\n\n", str); + printf("\nRECEIVED (xid=0x%X):\n%s\n\n", repl_xid, str); free(str); if (repl != NULL) { @@ -261,12 +263,13 @@ dpctl_transact_and_print(struct vconn *vconn, struct ofl_msg_header *req, static void dpctl_barrier(struct vconn *vconn) { struct ofl_msg_header *reply; + uint32_t repl_xid; char *str; struct ofl_msg_header req = {.type = OFPT_BARRIER_REQUEST}; - dpctl_transact(vconn, &req, &reply); + dpctl_transact(vconn, &req, &reply, &repl_xid); if (reply->type == OFPT_BARRIER_REPLY) { str = ofl_msg_to_string(reply, &dpctl_exp); @@ -274,7 +277,7 @@ dpctl_barrier(struct vconn *vconn) { free(str); } else { str = ofl_msg_to_string(reply, &dpctl_exp); - printf("\nRECEIVED:\n%s\n\n", str); + printf("\nRECEIVED (xid=0x%X):\n%s\n\n", repl_xid, str); free(str); } @@ -287,7 +290,7 @@ dpctl_send(struct vconn *vconn, struct ofl_msg_header *msg) { size_t buf_size; int error; - error = ofl_msg_pack(msg, XID, &buf, &buf_size, &dpctl_exp); + error = ofl_msg_pack(msg, global_xid, &buf, &buf_size, &dpctl_exp); if (error) { ofp_fatal(0, "Error packing request."); } @@ -308,7 +311,7 @@ static void dpctl_send_and_print(struct vconn *vconn, struct ofl_msg_header *msg) { char *str; str = ofl_msg_to_string(msg, &dpctl_exp); - printf("\nSENDING:\n%s\n\n", str); + printf("\nSENDING (xid=0x%X):\n%s\n\n", global_xid, str); free(str); dpctl_send(vconn, msg); @@ -319,6 +322,7 @@ ping(struct vconn *vconn, int argc, char *argv[]) { uint16_t payload_size = 0; size_t times = 0, i; struct ofl_msg_echo *reply; + uint32_t repl_xid; struct ofl_msg_echo req = {{.type = OFPT_ECHO_REQUEST}, @@ -349,7 +353,7 @@ ping(struct vconn *vconn, int argc, char *argv[]) { random_bytes(req.data, payload_size); gettimeofday(&start, NULL); - dpctl_transact(vconn, (struct ofl_msg_header *)&req, (struct ofl_msg_header **)&reply); + dpctl_transact(vconn, (struct ofl_msg_header *)&req, (struct ofl_msg_header **)&reply, &repl_xid); gettimeofday(&end, NULL); if ((req.data_length != reply->data_length) || @@ -1002,6 +1006,7 @@ parse_options(int argc, char *argv[]) {"strict", no_argument, 0, OPT_STRICT}, {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, + {"xid", required_argument, 0, 'x'}, VCONN_SSL_LONG_OPTIONS {0, 0, 0, 0}, }; @@ -1039,6 +1044,10 @@ parse_options(int argc, char *argv[]) vlog_set_verbosity(optarg); break; + case 'x': + global_xid = strtoul(optarg, NULL, 0); + break; + VCONN_SSL_OPTION_HANDLERS case '?': From dd6995c3c8c2811b761079f3f9e435aa8ae9f510 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 23 Aug 2013 16:56:27 -0700 Subject: [PATCH 047/191] Change default TCP port to 6653 (IANA official allocation) --- debian/openflow-controller.default | 4 ++-- debian/openflow-switch.template | 4 ++-- include/openflow/openflow.h | 4 ++-- secchan/ofprotocol.8.in | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/debian/openflow-controller.default b/debian/openflow-controller.default index 3b84b62a..03a19b0d 100644 --- a/debian/openflow-controller.default +++ b/debian/openflow-controller.default @@ -5,11 +5,11 @@ # 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 +# (default: 6653). 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. +# (default: 6653). 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 diff --git a/debian/openflow-switch.template b/debian/openflow-switch.template index f3f641e8..fe1aae79 100644 --- a/debian/openflow-switch.template +++ b/debian/openflow-switch.template @@ -69,8 +69,8 @@ SWITCH_IP=dhcp # 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 +# tcp:HOST[:PORT] via TCP to PORT (default: 6653) on HOST +# ssl:HOST[:PORT] via SSL to PORT (default: 6653) 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" diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 1c52618d..b6f0fb58 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -35,8 +35,8 @@ #define OFP_VERSION 0x04 #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_TCP_PORT 6653 +#define OFP_SSL_PORT 6653 #define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */ /* Number of tables in the pipeline */ #define PIPELINE_TABLES 64 diff --git a/secchan/ofprotocol.8.in b/secchan/ofprotocol.8.in index 4aae44a3..f1d85778 100644 --- a/secchan/ofprotocol.8.in +++ b/secchan/ofprotocol.8.in @@ -36,13 +36,13 @@ using the following forms: .TP \fBssl:\fIhost\fR[\fB:\fIport\fR] -The specified SSL \fIport\fR (default: 6633) on the given remote +The specified SSL \fIport\fR (default: 6653) 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 +The specified TCP \fIport\fR (default: 6653) on the given remote \fIhost\fR. .TP @@ -320,13 +320,13 @@ multiple connection methods. .RS .TP \fBpssl:\fR[\fIport\fR] -Listens for SSL connections on \fIport\fR (default: 6633). The +Listens for SSL connections on \fIport\fR (default: 6653). 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). +Listens for TCP connections on \fIport\fR (default: 6653). .TP \fBpunix:\fIfile\fR From bef2cfcd0efd91da6da5a36e150dad5c81a56029 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 23 Aug 2013 17:05:07 -0700 Subject: [PATCH 048/191] OXM_OF_IPV6_EXTHDR can't be used with set-field. --- oflib/ofl-actions-unpack.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/oflib/ofl-actions-unpack.c b/oflib/ofl-actions-unpack.c index 7a186ff1..f986e0ca 100644 --- a/oflib/ofl-actions-unpack.c +++ b/oflib/ofl-actions-unpack.c @@ -285,7 +285,9 @@ ofl_actions_unpack(struct ofp_action_header *src, size_t *len, struct ofl_action da->field->value = malloc(OXM_LENGTH(da->field->header)); /*TODO: need to check if other fields are valid */ if(da->field->header == OXM_OF_IN_PORT || da->field->header == OXM_OF_IN_PHY_PORT - || da->field->header == OXM_OF_METADATA){ + || da->field->header == OXM_OF_METADATA + || da->field->header == OXM_OF_IPV6_EXTHDR){ + return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_SET_TYPE); } switch(OXM_LENGTH(da->field->header)){ From 246e4de57cdb353d2038dea752be969aa0557331 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 23 Aug 2013 17:15:00 -0700 Subject: [PATCH 049/191] Allow dpctl to set ipv6_exthdr to trigger error message. --- utilities/dpctl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 3b9769dc..733d215d 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -1875,6 +1875,18 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { } return 0; } + if (strncmp(token, MATCH_EXT_HDR KEY_VAL2, strlen(MATCH_EXT_HDR KEY_VAL2)) == 0) { + uint32_t *ext_hdr = malloc(sizeof(uint32_t)); + if (parse32(token + strlen(MATCH_EXT_HDR KEY_VAL2), NULL, 0, 0xffffffff, ext_hdr)) { + ofp_fatal(0, "Error parsing ext_hdr: %s.", token); + } + else { + act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); + act->field->header = OXM_OF_IPV6_EXTHDR; + act->field->value = (uint8_t*) ext_hdr; + } + return 0; + } ofp_fatal(0, "Error parsing set_field arg: %s.", token); } From 795821c24796d260fbb2e48cfc8ace5947200bd0 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Tue, 28 Jan 2014 16:21:25 -0800 Subject: [PATCH 050/191] Implement OFPFF_RESET_COUNTS for flow-mod modify. --- udatapath/flow_entry.c | 13 +++++++++++++ udatapath/flow_entry.h | 3 +++ udatapath/flow_table.c | 1 + 3 files changed, 17 insertions(+) diff --git a/udatapath/flow_entry.c b/udatapath/flow_entry.c index d0719051..e361d982 100644 --- a/udatapath/flow_entry.c +++ b/udatapath/flow_entry.c @@ -150,6 +150,19 @@ flow_entry_replace_instructions(struct flow_entry *entry, init_group_refs(entry); } +void +flow_entry_modify_stats(struct flow_entry *entry, + struct ofl_msg_flow_mod *mod) { + + /* Reset flow counters as needed. Jean II */ + if ((mod->flags & OFPFF_RESET_COUNTS) != 0) { + if (!(entry->no_pkt_count)) + entry->stats->packet_count = 0; + if (!(entry->no_byt_count)) + entry->stats->byte_count = 0; + } +} + bool flow_entry_idle_timeout(struct flow_entry *entry) { bool timeout; diff --git a/udatapath/flow_entry.h b/udatapath/flow_entry.h index 0c893f0d..f411f904 100644 --- a/udatapath/flow_entry.h +++ b/udatapath/flow_entry.h @@ -83,6 +83,9 @@ void flow_entry_replace_instructions(struct flow_entry *entry, size_t instructions_num, struct ofl_instruction_header **instructions); +void +flow_entry_modify_stats(struct flow_entry *entry, + struct ofl_msg_flow_mod *mod); /* Checks if the entry should time out because of its idle timeout. If so, the * packet is freed, flow removed message is generated, and true is returned. */ diff --git a/udatapath/flow_table.c b/udatapath/flow_table.c index 971db7dd..0826fdf4 100644 --- a/udatapath/flow_table.c +++ b/udatapath/flow_table.c @@ -159,6 +159,7 @@ flow_table_modify(struct flow_table *table, struct ofl_msg_flow_mod *mod, bool s LIST_FOR_EACH (entry, struct flow_entry, match_node, &table->match_entries) { if (flow_entry_matches(entry, mod, strict, true/*check_cookie*/)) { flow_entry_replace_instructions(entry, mod->instructions_num, mod->instructions); + flow_entry_modify_stats(entry, mod); *insts_kept = true; } } From 2350fd90437add7a1a8ea2df991b800b5ac456f5 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 7 Feb 2014 14:04:23 -0800 Subject: [PATCH 051/191] EXT-387: Implement an exact-match 5 tupple table. --- udatapath/flow_table.c | 33 +++++++++++++++----- udatapath/pipeline.c | 69 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 8 deletions(-) diff --git a/udatapath/flow_table.c b/udatapath/flow_table.c index 0826fdf4..196b9ad3 100644 --- a/udatapath/flow_table.c +++ b/udatapath/flow_table.c @@ -82,6 +82,13 @@ struct ofl_action_header actions[] = { {OFPAT_OUTPUT, 4}, #define N_ACTIONS (sizeof(actions) / sizeof(struct ofl_action_header)) +uint32_t oxm_ids_60[]={OXM_OF_IP_PROTO, OXM_OF_IPV4_SRC, OXM_OF_IPV4_DST, OXM_OF_TCP_SRC, + OXM_OF_TCP_DST, OXM_OF_UDP_SRC, OXM_OF_UDP_DST}; +#define NUM_OXM_IDS_60 (sizeof(oxm_ids_60) / sizeof(uint32_t)) + +uint32_t wildcarded_60[] = {}; +#define NUM_WILD_IDS_60 (sizeof(wildcarded_60) / sizeof(uint32_t)) + /* When inserting an entry, this function adds the flow entry to the list of * hard and idle timeout entries, if appropriate. */ static void @@ -270,7 +277,7 @@ flow_table_timeout(struct flow_table *table) { static void -flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp_table_feature_prop_type type){ +flow_table_create_property(uint8_t table_id, struct ofl_table_feature_prop_header **prop, enum ofp_table_feature_prop_type type){ switch(type){ case OFPTFPT_INSTRUCTIONS: @@ -325,8 +332,13 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp int i; oxm_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); oxm_capabilities->header.type = type; - oxm_capabilities->oxm_num = NUM_OXM_IDS; - oxm_capabilities->oxm_ids = oxm_ids; + if (table_id != 60) { + oxm_capabilities->oxm_num = NUM_OXM_IDS; + oxm_capabilities->oxm_ids = oxm_ids; + } else { + oxm_capabilities->oxm_num = NUM_OXM_IDS_60; + oxm_capabilities->oxm_ids = oxm_ids_60; + } oxm_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&oxm_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) oxm_capabilities; break; @@ -335,8 +347,13 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp struct ofl_table_feature_prop_oxm *oxm_capabilities; oxm_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); oxm_capabilities->header.type = type; - oxm_capabilities->oxm_num = NUM_WILD_IDS; - oxm_capabilities->oxm_ids = wildcarded; + if (table_id != 60) { + oxm_capabilities->oxm_num = NUM_WILD_IDS; + oxm_capabilities->oxm_ids = wildcarded; + } else { + oxm_capabilities->oxm_num = NUM_WILD_IDS_60; + oxm_capabilities->oxm_ids = wildcarded_60; + } oxm_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&oxm_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) oxm_capabilities; break; @@ -349,14 +366,14 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp } static int -flow_table_features(struct ofl_table_features *features){ +flow_table_features(uint8_t table_id, struct ofl_table_features *features){ int type, j; features->properties = (struct ofl_table_feature_prop_header **) xmalloc(sizeof(struct ofl_table_feature_prop_header *) * TABLE_FEATURES_NUM); j = 0; for(type = OFPTFPT_INSTRUCTIONS; type <= OFPTFPT_APPLY_SETFIELD_MISS; type++){ //features->properties[j] = xmalloc(sizeof(struct ofl_table_feature_prop_header)); - flow_table_create_property(&features->properties[j], type); + flow_table_create_property(table_id, &features->properties[j], type); if(type == OFPTFPT_MATCH|| type == OFPTFPT_WILDCARDS){ type++; } @@ -396,7 +413,7 @@ flow_table_create(struct datapath *dp, uint8_t table_id) { table->features->metadata_write = 0xffffffffffffffff; table->features->config = OFPTC_TABLE_MISS_CONTROLLER; table->features->max_entries = FLOW_TABLE_MAX_ENTRIES; - table->features->properties_num = flow_table_features(table->features); + table->features->properties_num = flow_table_features(table_id, table->features); list_init(&table->match_entries); list_init(&table->hard_entries); diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index f2abec99..a867e1c2 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -240,6 +240,75 @@ pipeline_handle_flow_mod(struct pipeline *pl, struct ofl_msg_flow_mod *msg, return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNSUP_INST); } + /* Validate match for table 60 for exact match IP 5 tupples. */ + if ((msg->table_id == 60) && (msg->command == OFPFC_ADD)) { + struct ofl_match *match = (struct ofl_match *) msg->match; + size_t match_size = match->header.length; + int found_mask = 0; + /* Examine all match fields. */ + if (match_size) { + struct ofl_match_tlv *oxm; + HMAP_FOR_EACH(oxm, struct ofl_match_tlv, hmap_node, &match->match_fields){ + switch (oxm->header) { + case OXM_OF_IPV4_SRC_W: + case OXM_OF_IPV4_DST_W: + /* We can't accept a wildcarded version of those fields. + * Return an error. */ + VLOG_DBG(LOG_MODULE, "5 tupple validation : found masked field."); + return ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_NW_ADDR_MASK); +#if 0 + case OXM_OF_IP_PROTO_W: + case OXM_OF_TCP_SRC_W: + case OXM_OF_TCP_DST_W: + case OXM_OF_UDP_SRC_W: + case OXM_OF_UDP_DST_W: + /* We can't accept a wildcarded version of those fields. + * Return an error. */ + VLOG_DBG(LOG_MODULE, "5 tupple validation : found masked field."); + return ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_MASK); +#endif + + /* Check if we have all of our 5 tupple. */ + case OXM_OF_IP_PROTO: + found_mask |= 0x1; + break; + case OXM_OF_IPV4_SRC: + found_mask |= 0x2; + break; + case OXM_OF_IPV4_DST: + found_mask |= 0x4; + break; + case OXM_OF_TCP_SRC: + found_mask |= 0x8; + break; + case OXM_OF_TCP_DST: + found_mask |= 0x10; + break; + case OXM_OF_UDP_SRC: + found_mask |= 0x8; + break; + case OXM_OF_UDP_DST: + found_mask |= 0x10; + break; + + case OXM_OF_ETH_TYPE: + /* Must accept pre-requisite. */ + break; + + default: + /* All other fields not welcomed. */ + VLOG_DBG(LOG_MODULE, "5 tupple validation : found unwanted."); + return ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_FIELD); + } + } + } + VLOG_DBG(LOG_MODULE, "5 tupple validation : found_mask=0x%X.", found_mask); + if (found_mask != 0x1F) { + /* We need all 5 fields of the 5 tupple. */ + return ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } + } + if (msg->table_id == 0xff) { if (msg->command == OFPFC_DELETE || msg->command == OFPFC_DELETE_STRICT) { size_t i; From a382bb92a84bf29654e289497c9224c90c75f61a Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 31 Jan 2014 16:29:57 -0800 Subject: [PATCH 052/191] Make DSCP_REMARK increase drop precedence in IP packets (see EXT-416). --- udatapath/meter_entry.c | 62 ++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index d3044681..8a4db8d1 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -219,36 +219,48 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ b = choose_band(entry, *pkt); if(b != -1){ - struct ofl_meter_band_header *band_header = (struct ofl_meter_band_header*) entry->config->bands[b]; - switch(band_header->type){ - case OFPMBT_DROP:{ + struct ofl_meter_band_header *band_header = (struct ofl_meter_band_header*) entry->config->bands[b]; + switch(band_header->type){ + case OFPMBT_DROP:{ drop = true; - break; - } - case OFPMBT_DSCP_REMARK:{ - struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; - // descrease dscp in ipv4 header - struct ip_header *ipv4 = (*pkt)->handle_std->proto->ipv4; - uint8_t new_dscp = (ipv4->ip_tos >> 3) + band_header->prec_level; - uint8_t new_tos = (new_dscp << 3 ) | (ipv4->ip_tos & 0x03); - uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); - uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + new_tos); - ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); - ipv4->ip_tos = new_tos; - break; + break; + } + case OFPMBT_DSCP_REMARK:{ + /* Nothing prevent this band to be used for non-IP packets, so filter them out. Jean II */ + if ((*pkt)->handle_std->proto->ipv4 != NULL) { + struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; + // Fetch dscp in ipv4 header + struct ip_header *ipv4 = (*pkt)->handle_std->proto->ipv4; + uint8_t old_drop = ipv4->ip_tos & 0x1C; + /* The spec says that we need to increase + the drop precedence of the packet. + We need a valid DSCP out of the process, + so we can only modify dscp if the + drop precedence is low (tos 0x***010**) + or medium (tos 0x***100**). Jean II */ + if (((old_drop == 0x8) && (band_header->prec_level <= 2)) || ((old_drop == 0x10) && (band_header->prec_level <= 1))) { + uint8_t new_drop = old_drop + (band_header->prec_level << 3); + uint8_t new_tos = new_drop | (ipv4->ip_tos & 0xE3); + uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); + uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + new_tos); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_tos = new_tos; + } + } + break; } - case OFPMBT_EXPERIMENTER:{ - break; - } - } - entry->stats->band_stats[b]->byte_band_count += (*pkt)->buffer->size; - entry->stats->band_stats[b]->packet_band_count++; + case OFPMBT_EXPERIMENTER:{ + break; + } + } + entry->stats->band_stats[b]->byte_band_count += (*pkt)->buffer->size; + entry->stats->band_stats[b]->packet_band_count++; if (drop){ VLOG_ERR_RL(LOG_MODULE, &rl, "Dropping packet: rate %d", band_header->rate); - packet_destroy(*pkt); - *pkt = NULL; + packet_destroy(*pkt); + *pkt = NULL; } - } + } } From 71b51e30a6a7fcdbe752b5d0266e251c528e799e Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 3 Feb 2014 15:36:54 -0800 Subject: [PATCH 053/191] Properly handle error in table features. --- oflib/ofl-messages-unpack.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 80f53f20..440b72a4 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -816,6 +816,12 @@ ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os for(i = 0; i < dm->tables_num; i++){ error = ofl_structs_table_features_unpack((struct ofp_table_features*) features, len, &dm->table_features[i] , exp); + if (error) { + OFL_UTILS_FREE_ARR_FUN2(dm->table_features, i, + ofl_structs_free_table_features, exp); + free(dm); + return error; + } features += ntohs(((struct ofp_table_features*) features)->length); } *msg = (struct ofl_msg_header *)dm; @@ -1284,6 +1290,12 @@ ofl_msg_unpack_multipart_reply_table_features(struct ofp_multipart_reply *src, s for(i = 0; i < dm->tables_num; i++){ error = ofl_structs_table_features_unpack((struct ofp_table_features*) features, len, &dm->table_features[i] , exp); + if (error) { + OFL_UTILS_FREE_ARR_FUN2(dm->table_features, i, + ofl_structs_free_table_features, exp); + free(dm); + return error; + } features += ntohs(((struct ofp_table_features*) features)->length); } *msg = (struct ofl_msg_header *)dm; From f308c28242de57502f06d3dee80ce47ac17b6603 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 3 Feb 2014 15:50:22 -0800 Subject: [PATCH 054/191] Display table features errors. --- oflib/ofl-print.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/oflib/ofl-print.c b/oflib/ofl-print.c index 2974a54c..532aab77 100644 --- a/oflib/ofl-print.c +++ b/oflib/ofl-print.c @@ -347,6 +347,7 @@ ofl_error_type_print(FILE *stream, uint16_t type) { case (OFPET_METER_MOD_FAILED): { fprintf(stream, "METER_MOD_FAILED"); return; } case (OFPET_QUEUE_OP_FAILED): { fprintf(stream, "QUEUE_OP_FAILED"); return; } case (OFPET_SWITCH_CONFIG_FAILED): { fprintf(stream, "SWITCH_CONFIG_FAILED"); return; } + case (OFPET_TABLE_FEATURES_FAILED): { fprintf(stream, "TABLE_FEATURES_FAILED"); return; } default: { fprintf(stream, "?(%u)", type); return; } } } @@ -505,6 +506,17 @@ ofl_error_code_print(FILE *stream, uint16_t type, uint16_t code) { } break; } + case (OFPET_TABLE_FEATURES_FAILED): { + switch (code) { + case (OFPTFFC_BAD_TABLE) : { fprintf(stream, "BAD_TABLE"); return; } + case (OFPTFFC_BAD_METADATA) : { fprintf(stream, "BAD_METADATA"); return; } + case (OFPTFFC_BAD_TYPE) : { fprintf(stream, "BAD_TYPE"); return; } + case (OFPTFFC_BAD_LEN) : { fprintf(stream, "BAD_LEN"); return; } + case (OFPTFFC_BAD_ARGUMENT) : { fprintf(stream, "BAD_ARGUMENT"); return; } + case (OFPTFFC_EPERM) : { fprintf(stream, "EPERM"); return; } + } + break; + } } fprintf(stream, "?(%u)", code); } From f6bdeeb6c16a730838d7e226aee90883fc501521 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 3 Feb 2014 11:41:24 -0800 Subject: [PATCH 055/191] EXT-436: Pretend we don't support setting table-features and return an error. --- oflib/ofl-messages-unpack.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 440b72a4..29ba1dbb 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -806,6 +806,9 @@ ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os return 0; } +#if 1 + return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); +#else error = ofl_utils_count_ofp_table_features((uint8_t*) os->body, *len, &dm->tables_num); if (error) { free(dm); @@ -826,6 +829,7 @@ ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os } *msg = (struct ofl_msg_header *)dm; return 0; +#endif } static ofl_err From 761a02b5da6cac9469047a14738242e9398f1b56 Mon Sep 17 00:00:00 2001 From: ederlf Date: Tue, 29 Jul 2014 22:49:51 -0300 Subject: [PATCH 056/191] Fix missing reply xid to dpctl_transact --- utilities/dpctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 733d215d..659b5607 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -2812,9 +2812,10 @@ set_table_features_match(struct vconn *vconn, int argc, char *argv[]) { int t; int last_table; int batch_table; + uint32_t repl_xid; /* Extract current table features */ - dpctl_transact(vconn, (struct ofl_msg_header *)&req_init, &reply); + dpctl_transact(vconn, (struct ofl_msg_header *)&req_init, &reply, &repl_xid); table_feat = (struct ofl_msg_multipart_request_table_features *) reply; if (argc > 0) { From a54476ec91e929051c2a3789c8beb43264a0dfae Mon Sep 17 00:00:00 2001 From: ederlf Date: Tue, 29 Jul 2014 23:18:05 -0300 Subject: [PATCH 057/191] Fix lots of ugly warnings --- lib/netdev.c | 5 +++-- oflib/ofl-actions-print.c | 1 - oflib/ofl-messages-pack.c | 4 ++-- oflib/ofl-messages-print.c | 12 ++++++------ oflib/ofl-messages-unpack.c | 11 ++++------- oflib/ofl-messages.c | 3 ++- oflib/ofl-structs-print.c | 16 ++++++++++------ udatapath/datapath.c | 4 ++-- udatapath/pipeline.c | 12 ++++++------ utilities/dpctl.c | 6 +++--- 10 files changed, 38 insertions(+), 36 deletions(-) diff --git a/lib/netdev.c b/lib/netdev.c index 2674468d..76923f75 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -731,6 +731,7 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, int hwaddr_family; int error; struct netdev *netdev; + uint32_t val; init_netdev(); *netdev_ = NULL; @@ -745,10 +746,10 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, return errno; } #ifdef HAVE_PACKET_AUXDATA - uint32_t val = 1; + val = 1; if (setsockopt(netdev_fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof val) == -1 && errno != ENOPROTOOPT){ - VLOG_ERR(LOG_MODULE, "setsockopt(SO_RCVBUF,%zu): %s", val, strerror(errno)); + VLOG_ERR(LOG_MODULE, "setsockopt(SO_RCVBUF,%"PRIu32"): %s", val, strerror(errno)); } #endif diff --git a/oflib/ofl-actions-print.c b/oflib/ofl-actions-print.c index dd38ee25..7f8fa4a2 100644 --- a/oflib/ofl-actions-print.c +++ b/oflib/ofl-actions-print.c @@ -81,7 +81,6 @@ ofl_action_print(FILE *stream, struct ofl_action_header *act, struct ofl_exp *ex break; } case OFPAT_SET_FIELD:{ - size_t size; struct ofl_action_set_field *a = (struct ofl_action_set_field *)act; fprintf(stream, "{field:"); ofl_structs_oxm_tlv_print(stream, a->field); diff --git a/oflib/ofl-messages-pack.c b/oflib/ofl-messages-pack.c index 36329dd7..a28b3e42 100644 --- a/oflib/ofl-messages-pack.c +++ b/oflib/ofl-messages-pack.c @@ -100,9 +100,9 @@ ofl_msg_pack_role_status(struct ofl_msg_role_status *msg, uint8_t **buf, size_t *buf_len = sizeof(struct ofp_role_status); *buf = (uint8_t *)malloc(*buf_len); - sta = (struct ofl_msg_role_status *)(*buf); + sta = (struct ofp_role_status *)(*buf); sta->role = htonl(msg->role); - sta->reason = msg->reason; + sta->reason = msg->reason; memset(sta->pad,0,sizeof(sta->pad)); sta->generation_id = hton64(msg->generation_id); diff --git a/oflib/ofl-messages-print.c b/oflib/ofl-messages-print.c index 6afe8aa5..8142fea9 100644 --- a/oflib/ofl-messages-print.c +++ b/oflib/ofl-messages-print.c @@ -675,7 +675,7 @@ ofl_msg_print_queue_get_config_reply(struct ofl_msg_queue_get_config_reply *msg, static void ofl_msg_print_role_msg(struct ofl_msg_role_request *msg, FILE *stream){ - fprintf(stream, "{role= %d, generation_id= %lld}", msg->role, msg->generation_id); + fprintf(stream, "{role= %d, generation_id= %"PRIu64"}", msg->role, msg->generation_id); } @@ -683,7 +683,7 @@ ofl_msg_print_role_msg(struct ofl_msg_role_request *msg, FILE *stream){ static void ofl_msg_print_role_stats_msg(struct ofl_msg_role_status *msg, FILE * stream){ - fprintf(stream, "{role= %d, reason= %d, generation_id= %lld}", msg->role, msg->reason, msg->generation_id); + fprintf(stream, "{role= %d, reason= %d, generation_id= %"PRIu64"}", msg->role, msg->reason, msg->generation_id); } @@ -760,10 +760,10 @@ ofl_msg_print(FILE *stream, struct ofl_msg_header *msg, struct ofl_exp *exp) { ofl_msg_print_role_msg((struct ofl_msg_role_request*)msg, stream); } - /*modified by dingwanfu */ - case OFPT_ROLE_STATUS:{ - ofl_msg_print_role_stats_msg((struct ofl_msg_role_request*)msg, stream); - } + /*modified by dingwanfu */ + case OFPT_ROLE_STATUS:{ + ofl_msg_print_role_stats_msg((struct ofl_msg_role_status*)msg, stream); + } /* Queue Configuration messages. */ case OFPT_QUEUE_GET_CONFIG_REQUEST: { ofl_msg_print_queue_get_config_request((struct ofl_msg_queue_get_config_request *)msg, stream); return; } diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 29ba1dbb..32eec92e 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -131,7 +131,7 @@ ofl_msg_unpack_role_status(struct ofp_header *src, size_t *len, struct ofl_msg_h drl = (struct ofl_msg_role_status *) malloc(sizeof(struct ofl_msg_role_status)); drl->role = ntohl(srl->role); - drl->reason = srl->reason; + drl->reason = srl->reason; drl->generation_id = ntoh64(srl->generation_id); *msg = (struct ofl_msg_header *)drl; @@ -467,7 +467,7 @@ ofl_msg_unpack_flow_mod(struct ofp_header *src,uint8_t* buf, size_t *len, struct if (sm->table_id >= PIPELINE_TABLES && ((sm->command != OFPFC_DELETE || sm->command != OFPFC_DELETE_STRICT) && sm->table_id != OFPTT_ALL)) { - OFL_LOG_WARN(LOG_MODULE, "Received FLOW_MOD message has invalid table id (%zu).", sm->table_id ); + OFL_LOG_WARN(LOG_MODULE, "Received FLOW_MOD message has invalid table id (%d).", sm->table_id ); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_TABLE_ID); } @@ -701,7 +701,7 @@ ofl_msg_unpack_table_mod(struct ofp_header *src, size_t *len, struct ofl_msg_hea sm = (struct ofp_table_mod *)src; dm = (struct ofl_msg_table_mod *)malloc(sizeof(struct ofl_msg_table_mod)); if (sm->table_id >= PIPELINE_TABLES) { - OFL_LOG_WARN(LOG_MODULE, "Received TABLE_MOD message has invalid table id (%zu).", sm->table_id ); + OFL_LOG_WARN(LOG_MODULE, "Received TABLE_MOD message has invalid table id (%d).", sm->table_id ); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_TABLE_ID); } @@ -731,7 +731,7 @@ ofl_msg_unpack_multipart_request_flow(struct ofp_multipart_request *os, uint8_t* dm = (struct ofl_msg_multipart_request_flow *) malloc(sizeof(struct ofl_msg_multipart_request_flow)); if (sm->table_id != OFPTT_ALL && sm->table_id >= PIPELINE_TABLES) { - OFL_LOG_WARN(LOG_MODULE, "Received MULTIPART REQUEST FLOW message has invalid table id (%zu).", sm->table_id ); + OFL_LOG_WARN(LOG_MODULE, "Received MULTIPART REQUEST FLOW message has invalid table id (%d).", sm->table_id ); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_TABLE_ID); } @@ -794,9 +794,6 @@ ofl_msg_unpack_multipart_request_empty(struct ofp_multipart_request *os UNUSED, static ofl_err ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp){ struct ofl_msg_multipart_request_table_features *dm; - ofl_err error; - uint8_t *features; - size_t i; dm = (struct ofl_msg_multipart_request_table_features*) malloc(sizeof(struct ofl_msg_multipart_request_table_features)); if (!(*len)){ diff --git a/oflib/ofl-messages.c b/oflib/ofl-messages.c index d2c0f381..b1ddb2bd 100644 --- a/oflib/ofl-messages.c +++ b/oflib/ofl-messages.c @@ -277,7 +277,8 @@ ofl_msg_free(struct ofl_msg_header *msg, struct ofl_exp *exp) { break; } case OFPT_ROLE_REPLY: - case OFPT_ROLE_REQUEST:{ + case OFPT_ROLE_REQUEST: + case OFPT_ROLE_STATUS:{ break; } case OFPT_GET_ASYNC_REPLY: diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index 09c80126..830c6e23 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -398,9 +398,9 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0x1); break; case OFPXMT_OFB_METADATA: - fprintf(stream, "metadata=\"0x%llx\"", *((uint64_t*) f->value)); + fprintf(stream, "metadata=\"0x%"PRIu64"\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", metadata_mask=\"0x%llx\"", *((uint64_t*)(f->value+8))); + fprintf(stream, ", metadata_mask=\"0x%"PRIu64"\"", *((uint64_t*)(f->value+8))); } break; case OFPXMT_OFB_PBB_ISID : @@ -410,9 +410,9 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) } break; case OFPXMT_OFB_TUNNEL_ID: - fprintf(stream, "tunnel_id=\"%lld\"", *((uint64_t*) f->value)); + fprintf(stream, "tunnel_id=\"%"PRIu64"\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", tunnel_id_mask=\"%lld\"", *((uint64_t*)(f->value+8))); + fprintf(stream, ", tunnel_id_mask=\"%"PRIu64"\"", *((uint64_t*)(f->value+8))); } break; case OFPXMT_OFB_IPV6_EXTHDR: @@ -520,9 +520,13 @@ ofl_structs_queue_prop_print(FILE *stream, struct ofl_queue_prop_header *p) { fprintf(stream, "{rate=\"%u\"}", pm->rate); break; } - + case (OFPQT_MAX_RATE): { + break; + } + case (OFPQT_EXPERIMENTER): { + break; + } } - } char * diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 2dc5917a..581945f0 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -253,7 +253,7 @@ send_role_status_to_remote(struct datapath* dp) dp_send_message(dp, (struct ofl_msg_header *)&status, &rsender); } } - + return 0; } static void @@ -277,7 +277,7 @@ remote_run(struct datapath *dp, struct remote *r) static void remote_rconn_run(struct datapath *dp, struct remote *r, uint8_t conn_id) { - struct rconn *rconn; + struct rconn *rconn = NULL; ofl_err error; size_t i; diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index a867e1c2..4d5ca539 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -472,7 +472,7 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, return ofl_error(OFPET_BAD_REQUEST, OFPBRC_MULTIPART_BUFFER_OVERFLOW); } - VLOG_DBG(LOG_MODULE, "multipart request: merging with previous fragments (%d+%d)", ((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg)->tables_num, feat->tables_num); + VLOG_DBG(LOG_MODULE, "multipart request: merging with previous fragments (%zu+%zu)", ((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg)->tables_num, feat->tables_num); /* Merge the request with previous fragments. */ nomore = ofl_msg_merge_multipart_request_table_features((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg, feat); @@ -481,7 +481,7 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, if(!nomore) return 0; - VLOG_DBG(LOG_MODULE, "multipart request: reassembly complete (%d)", ((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg)->tables_num); + VLOG_DBG(LOG_MODULE, "multipart request: reassembly complete (%zu)", ((struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg)->tables_num); /* Use the complete request. */ feat = (struct ofl_msg_multipart_request_table_features *) sender->remote->mp_req_msg; @@ -500,7 +500,7 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, if(msg->flags & OFPMPF_REQ_MORE) { struct ofl_msg_multipart_request_table_features* saved_msg; - VLOG_DBG(LOG_MODULE, "multipart request: create reassembly buffer (%d)", feat->tables_num); + VLOG_DBG(LOG_MODULE, "multipart request: create reassembly buffer (%zu)", feat->tables_num); /* Create a buffer the do reassembly. */ saved_msg = (struct ofl_msg_multipart_request_table_features*) malloc(sizeof(struct ofl_msg_multipart_request_table_features)); @@ -519,7 +519,7 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, } /* Non fragmented request. Nothing to do... */ - VLOG_DBG(LOG_MODULE, "multipart request: non-fragmented request (%d)", feat->tables_num); + VLOG_DBG(LOG_MODULE, "multipart request: non-fragmented request (%zu)", feat->tables_num); } /*Check to see if the body is empty.*/ @@ -569,7 +569,7 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, features[i] = pl->tables[j]->features; j++; } - VLOG_DBG(LOG_MODULE, "multipart reply: returning %d tables, next table-id %d", i, j); + VLOG_DBG(LOG_MODULE, "multipart reply: returning %zu tables, next table-id %zu", i, j); { struct ofl_msg_multipart_reply_table_features reply = {{{.type = OFPT_MULTIPART_REPLY}, @@ -685,7 +685,7 @@ execute_entry(struct pipeline *pl, struct flow_entry *entry, hmap_node, hash_int(OXM_OF_METADATA,0), &(*pkt)->handle_std->match.match_fields){ uint64_t *metadata = (uint64_t*) f->value; *metadata = (*metadata & ~wi->metadata_mask) | (wi->metadata & wi->metadata_mask); - VLOG_DBG_RL(LOG_MODULE, &rl, "Executing write metadata: %llx", *metadata); + VLOG_DBG_RL(LOG_MODULE, &rl, "Executing write metadata: %"PRIu64"", *metadata); } break; } diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 659b5607..385bcbcb 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -2857,7 +2857,7 @@ set_table_features_match(struct vconn *vconn, int argc, char *argv[]) { { int features_len; - printf("\nJII table-num:%d\n", table_feat->tables_num); + printf("\nJII table-num:%zu\n", table_feat->tables_num); features_len = ofl_structs_table_features_ofp_total_len(table_feat->table_features, table_feat->tables_num, NULL); printf("\nJII features_len:%d\n", features_len); } @@ -2894,7 +2894,7 @@ set_table_features_match(struct vconn *vconn, int argc, char *argv[]) { /* Intermediate and last segment are not treated the same. Jean II */ if(t <= last_table) { - struct ofpbuf *ofpbufreq, *ofpbufrepl; + struct ofpbuf *ofpbufreq; uint8_t *bufreq; size_t bufreq_size; int error; @@ -2905,7 +2905,7 @@ set_table_features_match(struct vconn *vconn, int argc, char *argv[]) { if (error) { ofp_fatal(0, "Error packing request."); } - printf("\nJII-req-pack:%d\n", bufreq_size); + printf("\nJII-req-pack:%zu\n", bufreq_size); ofpbufreq = ofpbuf_new(0); ofpbuf_use(ofpbufreq, bufreq, bufreq_size); From 89446355df734f9087ac5c6c1920d3a604a9d555 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Aug 2014 16:00:50 -0700 Subject: [PATCH 058/191] Revert "EXT-436: Pretend we don't support setting table-features and return an error." This reverts commit f6bdeeb6c16a730838d7e226aee90883fc501521. This was prototyping code that cripple the switch. This was not supposed to be merged. --- oflib/ofl-messages-unpack.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 32eec92e..24573282 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -803,9 +803,6 @@ ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os return 0; } -#if 1 - return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); -#else error = ofl_utils_count_ofp_table_features((uint8_t*) os->body, *len, &dm->tables_num); if (error) { free(dm); @@ -826,7 +823,6 @@ ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os } *msg = (struct ofl_msg_header *)dm; return 0; -#endif } static ofl_err From cd4d52c6ee34d3ca3b2dd1e579b7d1db07817041 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Aug 2014 16:53:52 -0700 Subject: [PATCH 059/191] Fix revert of EXT-436, add back necessary local variables. --- oflib/ofl-messages-unpack.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 24573282..18e7f907 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -794,6 +794,9 @@ ofl_msg_unpack_multipart_request_empty(struct ofp_multipart_request *os UNUSED, static ofl_err ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp){ struct ofl_msg_multipart_request_table_features *dm; + ofl_err error; + uint8_t *features; + size_t i; dm = (struct ofl_msg_multipart_request_table_features*) malloc(sizeof(struct ofl_msg_multipart_request_table_features)); if (!(*len)){ From 8340db6f8d26ce5a46a593c16670059b012ee0f6 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Aug 2014 16:02:25 -0700 Subject: [PATCH 060/191] Revert "EXT-387: Implement an exact-match 5 tupple table." This reverts commit 2350fd90437add7a1a8ea2df991b800b5ac456f5. This was prototyping code that cripple the switch. This was not supposed to be merged. --- udatapath/flow_table.c | 33 +++++--------------- udatapath/pipeline.c | 69 ------------------------------------------ 2 files changed, 8 insertions(+), 94 deletions(-) diff --git a/udatapath/flow_table.c b/udatapath/flow_table.c index 196b9ad3..0826fdf4 100644 --- a/udatapath/flow_table.c +++ b/udatapath/flow_table.c @@ -82,13 +82,6 @@ struct ofl_action_header actions[] = { {OFPAT_OUTPUT, 4}, #define N_ACTIONS (sizeof(actions) / sizeof(struct ofl_action_header)) -uint32_t oxm_ids_60[]={OXM_OF_IP_PROTO, OXM_OF_IPV4_SRC, OXM_OF_IPV4_DST, OXM_OF_TCP_SRC, - OXM_OF_TCP_DST, OXM_OF_UDP_SRC, OXM_OF_UDP_DST}; -#define NUM_OXM_IDS_60 (sizeof(oxm_ids_60) / sizeof(uint32_t)) - -uint32_t wildcarded_60[] = {}; -#define NUM_WILD_IDS_60 (sizeof(wildcarded_60) / sizeof(uint32_t)) - /* When inserting an entry, this function adds the flow entry to the list of * hard and idle timeout entries, if appropriate. */ static void @@ -277,7 +270,7 @@ flow_table_timeout(struct flow_table *table) { static void -flow_table_create_property(uint8_t table_id, struct ofl_table_feature_prop_header **prop, enum ofp_table_feature_prop_type type){ +flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp_table_feature_prop_type type){ switch(type){ case OFPTFPT_INSTRUCTIONS: @@ -332,13 +325,8 @@ flow_table_create_property(uint8_t table_id, struct ofl_table_feature_prop_heade int i; oxm_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); oxm_capabilities->header.type = type; - if (table_id != 60) { - oxm_capabilities->oxm_num = NUM_OXM_IDS; - oxm_capabilities->oxm_ids = oxm_ids; - } else { - oxm_capabilities->oxm_num = NUM_OXM_IDS_60; - oxm_capabilities->oxm_ids = oxm_ids_60; - } + oxm_capabilities->oxm_num = NUM_OXM_IDS; + oxm_capabilities->oxm_ids = oxm_ids; oxm_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&oxm_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) oxm_capabilities; break; @@ -347,13 +335,8 @@ flow_table_create_property(uint8_t table_id, struct ofl_table_feature_prop_heade struct ofl_table_feature_prop_oxm *oxm_capabilities; oxm_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); oxm_capabilities->header.type = type; - if (table_id != 60) { - oxm_capabilities->oxm_num = NUM_WILD_IDS; - oxm_capabilities->oxm_ids = wildcarded; - } else { - oxm_capabilities->oxm_num = NUM_WILD_IDS_60; - oxm_capabilities->oxm_ids = wildcarded_60; - } + oxm_capabilities->oxm_num = NUM_WILD_IDS; + oxm_capabilities->oxm_ids = wildcarded; oxm_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&oxm_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) oxm_capabilities; break; @@ -366,14 +349,14 @@ flow_table_create_property(uint8_t table_id, struct ofl_table_feature_prop_heade } static int -flow_table_features(uint8_t table_id, struct ofl_table_features *features){ +flow_table_features(struct ofl_table_features *features){ int type, j; features->properties = (struct ofl_table_feature_prop_header **) xmalloc(sizeof(struct ofl_table_feature_prop_header *) * TABLE_FEATURES_NUM); j = 0; for(type = OFPTFPT_INSTRUCTIONS; type <= OFPTFPT_APPLY_SETFIELD_MISS; type++){ //features->properties[j] = xmalloc(sizeof(struct ofl_table_feature_prop_header)); - flow_table_create_property(table_id, &features->properties[j], type); + flow_table_create_property(&features->properties[j], type); if(type == OFPTFPT_MATCH|| type == OFPTFPT_WILDCARDS){ type++; } @@ -413,7 +396,7 @@ flow_table_create(struct datapath *dp, uint8_t table_id) { table->features->metadata_write = 0xffffffffffffffff; table->features->config = OFPTC_TABLE_MISS_CONTROLLER; table->features->max_entries = FLOW_TABLE_MAX_ENTRIES; - table->features->properties_num = flow_table_features(table_id, table->features); + table->features->properties_num = flow_table_features(table->features); list_init(&table->match_entries); list_init(&table->hard_entries); diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index 4d5ca539..1388a955 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -240,75 +240,6 @@ pipeline_handle_flow_mod(struct pipeline *pl, struct ofl_msg_flow_mod *msg, return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNSUP_INST); } - /* Validate match for table 60 for exact match IP 5 tupples. */ - if ((msg->table_id == 60) && (msg->command == OFPFC_ADD)) { - struct ofl_match *match = (struct ofl_match *) msg->match; - size_t match_size = match->header.length; - int found_mask = 0; - /* Examine all match fields. */ - if (match_size) { - struct ofl_match_tlv *oxm; - HMAP_FOR_EACH(oxm, struct ofl_match_tlv, hmap_node, &match->match_fields){ - switch (oxm->header) { - case OXM_OF_IPV4_SRC_W: - case OXM_OF_IPV4_DST_W: - /* We can't accept a wildcarded version of those fields. - * Return an error. */ - VLOG_DBG(LOG_MODULE, "5 tupple validation : found masked field."); - return ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_NW_ADDR_MASK); -#if 0 - case OXM_OF_IP_PROTO_W: - case OXM_OF_TCP_SRC_W: - case OXM_OF_TCP_DST_W: - case OXM_OF_UDP_SRC_W: - case OXM_OF_UDP_DST_W: - /* We can't accept a wildcarded version of those fields. - * Return an error. */ - VLOG_DBG(LOG_MODULE, "5 tupple validation : found masked field."); - return ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_MASK); -#endif - - /* Check if we have all of our 5 tupple. */ - case OXM_OF_IP_PROTO: - found_mask |= 0x1; - break; - case OXM_OF_IPV4_SRC: - found_mask |= 0x2; - break; - case OXM_OF_IPV4_DST: - found_mask |= 0x4; - break; - case OXM_OF_TCP_SRC: - found_mask |= 0x8; - break; - case OXM_OF_TCP_DST: - found_mask |= 0x10; - break; - case OXM_OF_UDP_SRC: - found_mask |= 0x8; - break; - case OXM_OF_UDP_DST: - found_mask |= 0x10; - break; - - case OXM_OF_ETH_TYPE: - /* Must accept pre-requisite. */ - break; - - default: - /* All other fields not welcomed. */ - VLOG_DBG(LOG_MODULE, "5 tupple validation : found unwanted."); - return ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_FIELD); - } - } - } - VLOG_DBG(LOG_MODULE, "5 tupple validation : found_mask=0x%X.", found_mask); - if (found_mask != 0x1F) { - /* We need all 5 fields of the 5 tupple. */ - return ofl_error(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); - } - } - if (msg->table_id == 0xff) { if (msg->command == OFPFC_DELETE || msg->command == OFPFC_DELETE_STRICT) { size_t i; From a781f1df3049fc826a974a753aaa9ff0811541b2 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Aug 2014 16:03:21 -0700 Subject: [PATCH 061/191] Revert "Allow dpctl to set ipv6_exthdr to trigger error message." This reverts commit 246e4de57cdb353d2038dea752be969aa0557331. This was prototyping code that is incorrect. This was not supposed to be merged. --- utilities/dpctl.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 385bcbcb..411c36e8 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -1875,18 +1875,6 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { } return 0; } - if (strncmp(token, MATCH_EXT_HDR KEY_VAL2, strlen(MATCH_EXT_HDR KEY_VAL2)) == 0) { - uint32_t *ext_hdr = malloc(sizeof(uint32_t)); - if (parse32(token + strlen(MATCH_EXT_HDR KEY_VAL2), NULL, 0, 0xffffffff, ext_hdr)) { - ofp_fatal(0, "Error parsing ext_hdr: %s.", token); - } - else { - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_IPV6_EXTHDR; - act->field->value = (uint8_t*) ext_hdr; - } - return 0; - } ofp_fatal(0, "Error parsing set_field arg: %s.", token); } From b07667d8ef96022980e02096468e45dcf101c90e Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 3 Feb 2014 11:52:24 -0800 Subject: [PATCH 062/191] Fix errors in ofl_structs_table_properties_unpack(). --- oflib/ofl-structs-unpack.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/oflib/ofl-structs-unpack.c b/oflib/ofl-structs-unpack.c index 755f9075..d9c8bf1e 100644 --- a/oflib/ofl-structs-unpack.c +++ b/oflib/ofl-structs-unpack.c @@ -226,7 +226,7 @@ ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, if (*len < ntohs(src->length)) { OFL_LOG_WARN(LOG_MODULE, "Received table property has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len); - return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); + return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_LEN); } plen = ntohs(src->length); @@ -340,7 +340,11 @@ ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, break; } + default: + OFL_LOG_WARN(LOG_MODULE, "The received property contained a unknown property (%zu).", ntohs(src->type)); + return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_TYPE); } + // must set type before check, so free works correctly prop->type = (enum ofp_table_feature_prop_type) ntohs(src->type); /* Make sure it can be reused for packing. Jean II */ From 3ca5b6d6b46515debe597ef24f9c543af8fa1e3f Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Tue, 4 Feb 2014 16:46:26 -0800 Subject: [PATCH 063/191] EXT-457: Insert MPLS header after VLAN headers. --- udatapath/dp_actions.c | 68 +++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 92506094..3b4acfa2 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -561,13 +561,16 @@ push_mpls(struct packet *pkt, struct ofl_action_push *act) { if (pkt->handle_std->proto->eth != NULL) { struct eth_header *eth, *new_eth; struct snap_header *snap, *new_snap; + struct vlan_header *vlan, *new_vlan; struct mpls_header *mpls, *new_mpls, *push_mpls; - struct ip_header *ipv4; - struct ipv6_header *ipv6; + struct ip_header *ipv4, *new_ipv4; + struct ipv6_header *ipv6, *new_ipv6; size_t eth_size; + size_t head_offset; eth = pkt->handle_std->proto->eth; snap = pkt->handle_std->proto->eth_snap; + vlan = pkt->handle_std->proto->vlan_last; mpls = pkt->handle_std->proto->mpls; ipv4 = pkt->handle_std->proto->ipv4; ipv6 = pkt->handle_std->proto->ipv6; @@ -576,19 +579,24 @@ push_mpls(struct packet *pkt, struct ofl_action_push *act) { ? ETH_HEADER_LEN : ETH_HEADER_LEN + LLC_HEADER_LEN + SNAP_HEADER_LEN; + head_offset = vlan == NULL ? eth_size + : (uint8_t *)vlan - (uint8_t *)eth + VLAN_HEADER_LEN; + if (ofpbuf_headroom(pkt->buffer) >= MPLS_HEADER_LEN) { // there is available space in headroom, move eth backwards pkt->buffer->data = (uint8_t *)(pkt->buffer->data) - MPLS_HEADER_LEN; pkt->buffer->size += MPLS_HEADER_LEN; - memmove(pkt->buffer->data, eth, eth_size); - + memmove(pkt->buffer->data, eth, head_offset); new_eth = (struct eth_header *)(pkt->buffer->data); new_snap = snap == NULL ? NULL - : (struct snap_header *)((uint8_t *)new_eth - + ETH_HEADER_LEN + MPLS_HEADER_LEN + LLC_HEADER_LEN); - push_mpls = (struct mpls_header *)((uint8_t *)new_eth + eth_size); + : (struct snap_header *)((uint8_t *)snap - MPLS_HEADER_LEN); + new_vlan = vlan == NULL ? NULL + : (struct vlan_header *)((uint8_t *)vlan - MPLS_HEADER_LEN); + push_mpls = (struct mpls_header *)((uint8_t *)new_eth + head_offset); new_mpls = mpls; + new_ipv4 = ipv4; + new_ipv6 = ipv6; } else { // not enough headroom, use tailroom of the packet @@ -598,39 +606,51 @@ push_mpls(struct packet *pkt, struct ofl_action_push *act) { new_eth = (struct eth_header *)(pkt->buffer->data); new_snap = snap == NULL ? NULL - : (struct snap_header *)((uint8_t *)new_eth - + ETH_HEADER_LEN + MPLS_HEADER_LEN + LLC_HEADER_LEN); - push_mpls = (struct mpls_header *)((uint8_t *)new_eth + ETH_HEADER_LEN); + : (struct snap_header *)((uint8_t *)snap - (uint8_t *)eth + (uint8_t *)new_eth); + new_vlan = vlan == NULL ? NULL + : (struct vlan_header *)((uint8_t *)vlan - (uint8_t *)eth + (uint8_t *)new_eth); + push_mpls = (struct mpls_header *)((uint8_t *)new_eth + head_offset); // push data to create space for new MPLS memmove((uint8_t *)push_mpls + MPLS_HEADER_LEN, push_mpls, - pkt->buffer->size - ETH_HEADER_LEN); - - new_mpls = mpls == NULL ? NULL - : (struct mpls_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); + pkt->buffer->size - head_offset); + + new_mpls = mpls == NULL ? NULL + : (struct mpls_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); + // Note: if ipv4 was not null, then there was no MPLS header in 1.1 + new_ipv4 = ipv4 == NULL ? NULL + : (struct ip_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); + new_ipv6 = ipv6 == NULL ? NULL + : (struct ip_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); } if (new_mpls != NULL) { push_mpls->fields = new_mpls->fields & ~htonl(MPLS_S_MASK); - } else if (ipv4 != NULL) { + } else if (new_ipv4 != NULL) { // copy IP TTL to MPLS TTL (rest is zero), and set S bit - push_mpls->fields = htonl((uint32_t)ipv4->ip_ttl & MPLS_TTL_MASK) | htonl(MPLS_S_MASK); - } else if (ipv6 != NULL) { + push_mpls->fields = htonl((uint32_t)new_ipv4->ip_ttl & MPLS_TTL_MASK) | htonl(MPLS_S_MASK); + } else if (new_ipv6 != NULL) { // copy IP HOP LIMIT to MPLS TTL (rest is zero), and set S bit - push_mpls->fields = htonl((uint32_t)ipv6->ipv6_hop_limit & MPLS_TTL_MASK) | htonl(MPLS_S_MASK); - } - else { + push_mpls->fields = htonl((uint32_t)new_ipv6->ipv6_hop_limit & MPLS_TTL_MASK) | htonl(MPLS_S_MASK); + } else { push_mpls->fields = htonl(MPLS_S_MASK); } - if (new_snap != NULL) { - new_snap->snap_type = ntohs(act->ethertype); + if (new_vlan != NULL) { + new_vlan->vlan_next_type = htons(act->ethertype); + } else if (new_snap != NULL) { + new_snap->snap_type = htons(act->ethertype); } else { - new_eth->eth_type = ntohs(act->ethertype); + new_eth->eth_type = htons(act->ethertype); } - pkt->handle_std->valid = false; + if (new_snap != NULL) { + new_eth->eth_type = htons(ntohs(new_eth->eth_type) + MPLS_HEADER_LEN); + } + // in 1.1 all proto but eth and mpls will be hidden, + // so revalidating won't be a tedious work (probably) + pkt->handle_std->valid = false; } else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute PUSH_MPLS action on packet with no eth."); } From e0de5dce3d9b0f2b0aa239432b5827c28e1d2003 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Aug 2014 16:34:14 -0700 Subject: [PATCH 064/191] Revert "Remove OFPCRR_MASTER_FAIL which is not defined by the spec." This reverts commit 385d29c25190495a0f966e6364a8f0f0afeb3141. This is a 1.4.X feature. This was not supposed to be merged. --- include/openflow/openflow.h | 1 + udatapath/datapath.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index b6f0fb58..bf4e0a4a 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -1776,6 +1776,7 @@ enum ofp_controller_role_reason { OFPCRR_MASTER_REQUEST = 0, /* Another controller asked to be master. */ OFPCRR_CONFIG = 1, /* Configuration changed on the switch. */ OFPCRR_EXPERIMENTER = 2, /* Experimenter data changed. */ + OFPCRR_MASTER_FAIL = 3, /* Master controller connection fail. */ }; diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 581945f0..e4eb1913 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -232,7 +232,7 @@ dp_run(struct datapath *dp) { } /*modified by dingwanfu for EXT-276*/ -/* send role_status (OFPCRR_EXPERIMENTER) information to remote controllers when master is done*/ +/* send role_status (MASTER_FAIL) information to remote controllers when master is done*/ static int send_role_status_to_remote(struct datapath* dp) { @@ -241,11 +241,11 @@ send_role_status_to_remote(struct datapath* dp) LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { if (r->role != OFPCR_ROLE_MASTER) { - /* Send ROLE_STATUS (OFPCRR_EXPERIMENTER) message to other controllers */ + /* Send ROLE_STATUS (MASTER_FAIL) message to other controllers */ struct ofl_msg_role_status status = {{.type = OFPT_ROLE_STATUS}, .role = r->role, - .reason = OFPCRR_EXPERIMENTER, + .reason = OFPCRR_MASTER_FAIL, .generation_id = dp->generation_id}; struct sender rsender = { .remote = r, From 75da80efb56b8dd43c37ba7a34ed402787501131 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Aug 2014 16:37:18 -0700 Subject: [PATCH 065/191] Revert "Send gratuitous role status message on master loss (from Dingwanfu - Huawei)." This reverts commit aa85c03faeb67db28f847184b15f4918459609df. This is a 1.4.X feature. This was not supposed to be merged. --- include/openflow/openflow.h | 1 - udatapath/datapath.c | 28 ---------------------------- 2 files changed, 29 deletions(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index bf4e0a4a..b6f0fb58 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -1776,7 +1776,6 @@ enum ofp_controller_role_reason { OFPCRR_MASTER_REQUEST = 0, /* Another controller asked to be master. */ OFPCRR_CONFIG = 1, /* Configuration changed on the switch. */ OFPCRR_EXPERIMENTER = 2, /* Experimenter data changed. */ - OFPCRR_MASTER_FAIL = 3, /* Master controller connection fail. */ }; diff --git a/udatapath/datapath.c b/udatapath/datapath.c index e4eb1913..e4830e0f 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -231,40 +231,12 @@ dp_run(struct datapath *dp) { } } -/*modified by dingwanfu for EXT-276*/ -/* send role_status (MASTER_FAIL) information to remote controllers when master is done*/ -static int -send_role_status_to_remote(struct datapath* dp) -{ - struct remote* r; - - LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { - if (r->role != OFPCR_ROLE_MASTER) { - - /* Send ROLE_STATUS (MASTER_FAIL) message to other controllers */ - struct ofl_msg_role_status status = - {{.type = OFPT_ROLE_STATUS}, - .role = r->role, - .reason = OFPCRR_MASTER_FAIL, - .generation_id = dp->generation_id}; - struct sender rsender = { - .remote = r, - .xid = 0}; - dp_send_message(dp, (struct ofl_msg_header *)&status, &rsender); - } - } - return 0; -} - static void remote_run(struct datapath *dp, struct remote *r) { remote_rconn_run(dp, r, MAIN_CONNECTION); if (!rconn_is_alive(r->rconn)) { - /*modified by dingwanfu for EXT-276*/ - if (r->role == OFPCR_ROLE_MASTER) - send_role_status_to_remote(dp); remote_destroy(r); return; } From aa74ab72401be356706f8eca47a9c15b9d372209 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Aug 2014 16:37:41 -0700 Subject: [PATCH 066/191] Revert "Fix typo preventing compile." This reverts commit 4918dfaaab6a535298f4b8206826bdaf50142d10. This is a 1.4.X feature. This was not supposed to be merged. --- include/openflow/openflow.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index b6f0fb58..e06d3b35 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -1517,7 +1517,7 @@ struct ofp_role_prop_expermenter { uint32_t experimenter_data[0]; }; OFP_ASSERT(sizeof(struct ofp_role_prop_expermenter) ==12); - +D /*modified by dingwanfu*/ /* Role status event message. */ struct ofp_role_status { From 0f4277e25e1094309a4157d82262c866e544890e Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Aug 2014 16:41:20 -0700 Subject: [PATCH 067/191] Revert "Role status events (from Dingwanfu - Huawei)." This reverts commit 786455f1619fe074705bb7d77340d95e25308991. This is a 1.4.X feature. This was not supposed to be merged. --- include/openflow/openflow.h | 58 ------------------------------------- oflib/ofl-messages-pack.c | 25 +--------------- oflib/ofl-messages-print.c | 15 +--------- oflib/ofl-messages-unpack.c | 24 --------------- oflib/ofl-messages.h | 10 ------- udatapath/datapath.c | 15 ---------- 6 files changed, 2 insertions(+), 145 deletions(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index e06d3b35..cd28aabc 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -93,9 +93,6 @@ enum ofp_type { OFPT_SET_ASYNC = 28, /* Controller/switch message */ /* Meters and rate limiters configuration messages. */ OFPT_METER_MOD = 29, /* Controller/switch message */ - - /*modified by dingwanfu*/ - OFPT_ROLE_STATUS =30, /* Async message */ }; /* OFPT_HELLO. This message has an empty body, but implementations must @@ -1495,44 +1492,6 @@ struct ofp_error_msg { }; OFP_ASSERT(sizeof(struct ofp_error_msg) == 12); -/*modified by dingwanfu*/ -/* Common header for Role Properties */ -struct ofp_role_prop_header { - uint16_t type; /* One of OFPRPT_*. */ - uint16_t length; /* Length in bytes of the properity. */ -}; -OFP_ASSERT(sizeof(struct ofp_role_prop_header) ==4); - -/*modified by dingwanfu*/ -/* Experimenter role property */ -struct ofp_role_prop_expermenter { - uint16_t type; - uint16_t length; - uint32_t experimenter; - uint32_t exp_type; - /* Followed by : - * -Exactly (length -12) bytes containing the experimenter data, then - * -Exactly (length + 7)/8*8 - (length) (between 0 - 7) bytes of all-zero bytes */ - - uint32_t experimenter_data[0]; -}; -OFP_ASSERT(sizeof(struct ofp_role_prop_expermenter) ==12); -D -/*modified by dingwanfu*/ -/* Role status event message. */ -struct ofp_role_status { - struct ofp_header header; /* Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. */ - uint32_t role; /* One of OFPCR_ROLE_*. */ - uint8_t reason; /* One of OFPCR_*. */ - uint8_t pad[3]; /* Align to 64 bits. */ - uint64_t generation_id; /* Master Election Generation Id */ - - /* Role Property list */ - struct ofp_role_prop_header properties[0]; -}; -OFP_ASSERT(sizeof(struct ofp_role_status) == 24); - - /* 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). */ @@ -1769,23 +1728,6 @@ enum ofp_table_features_failed_code { OFPTFFC_EPERM = 5, /* Permissions error. */ }; - -/*modified by dingwanfu*/ -/* What changed about controller role */ -enum ofp_controller_role_reason { - OFPCRR_MASTER_REQUEST = 0, /* Another controller asked to be master. */ - OFPCRR_CONFIG = 1, /* Configuration changed on the switch. */ - OFPCRR_EXPERIMENTER = 2, /* Experimenter data changed. */ -}; - - -/*modified by dingwanfu*/ -/* Role property types. */ -enum ofp_role_prop_type { - OFPCRT_EXPERIMENTER = 0xFFFF, /* Experimenter property. */ -}; - - /* OFPET_EXPERIMENTER: Error message (datapath -> controller). */ struct ofp_error_experimenter_msg { struct ofp_header header; diff --git a/oflib/ofl-messages-pack.c b/oflib/ofl-messages-pack.c index a28b3e42..234f865e 100644 --- a/oflib/ofl-messages-pack.c +++ b/oflib/ofl-messages-pack.c @@ -93,23 +93,6 @@ ofl_msg_pack_role_request(struct ofl_msg_role_request *msg, uint8_t **buf, size_ return 0; } -/*modified by dingwanfu*/ -static int -ofl_msg_pack_role_status(struct ofl_msg_role_status *msg, uint8_t **buf, size_t *buf_len) { - struct ofp_role_status *sta; - *buf_len = sizeof(struct ofp_role_status); - *buf = (uint8_t *)malloc(*buf_len); - - sta = (struct ofp_role_status *)(*buf); - sta->role = htonl(msg->role); - sta->reason = msg->reason; - memset(sta->pad,0,sizeof(sta->pad)); - sta->generation_id = hton64(msg->generation_id); - - return 0; -} - - static int ofl_msg_pack_features_reply(struct ofl_msg_features_reply *msg, uint8_t **buf, size_t *buf_len) { struct ofp_switch_features *features; @@ -1122,15 +1105,9 @@ ofl_msg_pack(struct ofl_msg_header *msg, uint32_t xid, uint8_t **buf, size_t *bu break; } case OFPT_ROLE_REQUEST: - case OFPT_ROLE_REPLY: { + case OFPT_ROLE_REPLY: error = ofl_msg_pack_role_request((struct ofl_msg_role_request*)msg, buf, buf_len); - break;/*modified by dignwanfu*/ - } - /*modified by dignwanfu*/ - case OFPT_ROLE_STATUS:{ - error = ofl_msg_pack_role_status((struct ofl_msg_role_status*)msg, buf, buf_len); break; - } default: { OFL_LOG_WARN(LOG_MODULE, "Trying to pack unknown message type."); error = -1; diff --git a/oflib/ofl-messages-print.c b/oflib/ofl-messages-print.c index 8142fea9..4b6c1e34 100644 --- a/oflib/ofl-messages-print.c +++ b/oflib/ofl-messages-print.c @@ -679,14 +679,6 @@ ofl_msg_print_role_msg(struct ofl_msg_role_request *msg, FILE *stream){ } -/*modified by dingwanfu*/ -static void -ofl_msg_print_role_stats_msg(struct ofl_msg_role_status *msg, FILE * stream){ - - fprintf(stream, "{role= %d, reason= %d, generation_id= %"PRIu64"}", msg->role, msg->reason, msg->generation_id); - -} - static void ofl_msg_print_async(struct ofl_msg_async_config* msg, FILE *stream){ @@ -759,12 +751,6 @@ ofl_msg_print(FILE *stream, struct ofl_msg_header *msg, struct ofl_exp *exp) { case OFPT_ROLE_REPLY:{ ofl_msg_print_role_msg((struct ofl_msg_role_request*)msg, stream); } - - /*modified by dingwanfu */ - case OFPT_ROLE_STATUS:{ - ofl_msg_print_role_stats_msg((struct ofl_msg_role_status*)msg, stream); - } - /* Queue Configuration messages. */ case OFPT_QUEUE_GET_CONFIG_REQUEST: { ofl_msg_print_queue_get_config_request((struct ofl_msg_queue_get_config_request *)msg, stream); return; } case OFPT_QUEUE_GET_CONFIG_REPLY: { ofl_msg_print_queue_get_config_reply((struct ofl_msg_queue_get_config_reply *)msg, stream); return; } @@ -773,6 +759,7 @@ ofl_msg_print(FILE *stream, struct ofl_msg_header *msg, struct ofl_exp *exp) { case OFPT_GET_ASYNC_REQUEST:{return;} case OFPT_GET_ASYNC_REPLY: case OFPT_SET_ASYNC:{ofl_msg_print_async((struct ofl_msg_async_config*)msg, stream); return;} + case OFPT_METER_MOD: {ofl_msg_print_meter_mod((struct ofl_msg_meter_mod*)msg, stream); return;} } diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 18e7f907..0b2a582b 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -114,30 +114,6 @@ ofl_msg_unpack_role_request(struct ofp_header *src, size_t *len, struct ofl_msg_ return 0; } -/*modified by dingwanfu*/ -static int -ofl_msg_unpack_role_status(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { - - struct ofp_role_status * srl; - struct ofl_msg_role_status * drl; - - if (*len < sizeof(struct ofp_role_status)){ - OFL_LOG_WARN(LOG_MODULE, "Received ROLE_STATUS message has invalid length (%zu).", *len); - return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - *len -= sizeof(struct ofp_role_status); - - srl = (struct ofp_role_status *) src; - drl = (struct ofl_msg_role_status *) malloc(sizeof(struct ofl_msg_role_status)); - - drl->role = ntohl(srl->role); - drl->reason = srl->reason; - drl->generation_id = ntoh64(srl->generation_id); - - *msg = (struct ofl_msg_header *)drl; - return 0; -} - static ofl_err ofl_msg_unpack_features_reply(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { struct ofp_switch_features *sr; diff --git a/oflib/ofl-messages.h b/oflib/ofl-messages.h index ddacdb96..39770730 100644 --- a/oflib/ofl-messages.h +++ b/oflib/ofl-messages.h @@ -125,17 +125,7 @@ struct ofl_msg_role_request { uint64_t generation_id; /* Master Election Generation Id */ }; -/*modified by dingwanfu*/ -struct ofl_msg_role_status { - struct ofp_header header; /* Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. */ - uint32_t role; /* One of OFPCR_ROLE_*. */ - uint8_t reason; /* One of OFPCR_*. */ - uint8_t pad[3]; /* Align to 64 bits. */ - uint64_t generation_id; /* Master Election Generation Id */ - /* Role Property list */ - struct ofp_role_prop_header properties[0]; -}; /************************ * Asynchronous messages diff --git a/udatapath/datapath.c b/udatapath/datapath.c index e4830e0f..6343a466 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -624,21 +624,6 @@ dp_handle_role_request(struct datapath *dp, struct ofl_msg_role_request *msg, LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { if (r->role == OFPCR_ROLE_MASTER) { r->role = OFPCR_ROLE_SLAVE; - - /*modified by dingwanfu*/ - /* Send ROLE_STATUS message to old master(s) */ - if (r != sender->remote){ /* Do not send message to the request controller */ - struct ofl_msg_role_status status = - {{.type = OFPT_ROLE_STATUS}, - .role = OFPCR_ROLE_SLAVE, - .reason = OFPCRR_MASTER_REQUEST, - .generation_id = msg->generation_id}; - struct sender rsender = { - .remote = r, - .xid = 0}; - dp_send_message(dp, (struct ofl_msg_header *)&status, &rsender); - } - } } sender->remote->role = OFPCR_ROLE_MASTER; From bd8e7b68951c5ef2293d0a0e45c89b265a2eba17 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Aug 2014 16:50:09 -0700 Subject: [PATCH 068/191] Finish reverting EXT-192/EXT-276 Role Status (1.4 feature). --- oflib/ofl-messages.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/oflib/ofl-messages.c b/oflib/ofl-messages.c index b1ddb2bd..d2c0f381 100644 --- a/oflib/ofl-messages.c +++ b/oflib/ofl-messages.c @@ -277,8 +277,7 @@ ofl_msg_free(struct ofl_msg_header *msg, struct ofl_exp *exp) { break; } case OFPT_ROLE_REPLY: - case OFPT_ROLE_REQUEST: - case OFPT_ROLE_STATUS:{ + case OFPT_ROLE_REQUEST:{ break; } case OFPT_GET_ASYNC_REPLY: From 36738aeb3501f66fb382e7b59138c88e8843b19c Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 25 Aug 2014 17:00:13 -0700 Subject: [PATCH 069/191] Fix a few more warnings. --- oflib/ofl-structs-unpack.c | 6 +++--- oflib/oxm-match.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/oflib/ofl-structs-unpack.c b/oflib/ofl-structs-unpack.c index d9c8bf1e..19ada818 100644 --- a/oflib/ofl-structs-unpack.c +++ b/oflib/ofl-structs-unpack.c @@ -193,7 +193,7 @@ ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct break; } default: - OFL_LOG_WARN(LOG_MODULE, "The received instruction type (%zu) is invalid.", ntohs(src->type)); + OFL_LOG_WARN(LOG_MODULE, "The received instruction type (%u) is invalid.", ntohs(src->type)); return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNKNOWN_INST); } @@ -214,7 +214,7 @@ ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct } static ofl_err -ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, size_t *len, struct ofl_table_feature_prop_header **dst, struct ofl_exp *exp){ +ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, size_t *len, struct ofl_table_feature_prop_header **dst, struct ofl_exp *exp UNUSED){ size_t plen; ofl_err error; struct ofl_table_feature_prop_header * prop = NULL; @@ -341,7 +341,7 @@ ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, break; } default: - OFL_LOG_WARN(LOG_MODULE, "The received property contained a unknown property (%zu).", ntohs(src->type)); + OFL_LOG_WARN(LOG_MODULE, "The received property contained a unknown property (%u).", ntohs(src->type)); return ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_TYPE); } diff --git a/oflib/oxm-match.c b/oflib/oxm-match.c index e21edaaa..0d4fc4e9 100644 --- a/oflib/oxm-match.c +++ b/oflib/oxm-match.c @@ -472,7 +472,7 @@ oxm_pull_match(struct ofpbuf *buf, struct ofl_match * match_dst, int match_len) if (!p) { VLOG_DBG_RL(LOG_MODULE,&rl, "oxm_match length %u, rounded up to a " "multiple of 8, is longer than space in message (max " - "length %d)", match_len, buf->size); + "length %zd)", match_len, buf->size); return ofp_mkerr(OFPET_BAD_MATCH, OFPBRC_BAD_LEN); } From 452a6c71e2d24a88a49e62d1f3e5f1f7c6d4f0b1 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Fri, 29 Aug 2014 22:16:30 -0300 Subject: [PATCH 070/191] Add the case of a following IPv6 header for copy ttl in and out action. This commit adds the copy ttl out and in for the case of an IPv6 header following an MPLS header. --- lib/dhcp-client.c | 2 +- lib/packets.h | 5 ++-- udatapath/dp_actions.c | 57 ++++++++++++++++++++++++++---------------- 3 files changed, 39 insertions(+), 25 deletions(-) diff --git a/lib/dhcp-client.c b/lib/dhcp-client.c index b97af0d8..3c7b33da 100644 --- a/lib/dhcp-client.c +++ b/lib/dhcp-client.c @@ -997,7 +997,7 @@ do_send_msg(struct dhclient *cli, const struct dhcp_msg *msg) memcpy(eh.eth_dst, eth_addr_broadcast, ETH_ADDR_LEN); eh.eth_type = htons(ETH_TYPE_IP); - nh.ip_ihl_ver = IP_IHL_VER(5, IP_VERSION); + nh.ip_ihl_ver = IP_IHL_VER(5, IPV4_VERSION); nh.ip_tos = 0; nh.ip_tot_len = htons(IP_HEADER_LEN + UDP_HEADER_LEN + b.size); /* We can't guarantee uniqueness of ip_id versus the host's, screwing up diff --git a/lib/packets.h b/lib/packets.h index 0868c424..b92aa7f2 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -221,8 +221,7 @@ BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header)); -#define IP_VERSION 4 - +#define IPV4_VERSION 4 #define IP_DONT_FRAGMENT 0x4000 /* Don't fragment. */ #define IP_MORE_FRAGMENTS 0x2000 /* More fragments. */ #define IP_FRAG_OFF_MASK 0x1fff /* Fragment offset. */ @@ -259,8 +258,8 @@ BUILD_ASSERT_DECL(IP_HEADER_LEN == sizeof(struct ip_header)); #define IPV6_TC(ipv6_ver_tc_fl) ((ipv6_ver_tc_fl) & 0xff00000) #define IPV6_FLABEL(ipv6_ver_tc_fl) ((ipv6_ver_tc_fl) & 0xffff) +#define IPV6_VERSION 6 #define IPV6_FLABEL_MASK 0xfffff - #define IPV6_HEADER_LEN 40 struct ipv6_header { uint32_t ipv6_ver_tc_fl; diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 3b4acfa2..316c3575 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -365,21 +365,27 @@ static void copy_ttl_out(struct packet *pkt, struct ofl_action_header *act UNUSED) { packet_handle_std_validate(pkt->handle_std); if (pkt->handle_std->proto->mpls != NULL) { - struct mpls_header *mpls = pkt->handle_std->proto->mpls; - + struct mpls_header *mpls = pkt->handle_std->proto->mpls; if ((ntohl(mpls->fields) & MPLS_S_MASK) == 0) { // There is an inner MPLS header struct mpls_header *in_mpls = (struct mpls_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); - mpls->fields = (mpls->fields & ~htonl(MPLS_TTL_MASK)) | (in_mpls->fields & htonl(MPLS_TTL_MASK)); - } else if (pkt->buffer->size >= ETH_HEADER_LEN + MPLS_HEADER_LEN + IP_HEADER_LEN) { - // Assumes an IPv4 header follows, if there is place for it - struct ip_header *ipv4 = (struct ip_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); - - mpls->fields = (mpls->fields & ~htonl(MPLS_TTL_MASK)) | htonl((uint32_t)ipv4->ip_ttl & MPLS_TTL_MASK); - - } else { + } else if (pkt->buffer->size >= ETH_HEADER_LEN + MPLS_HEADER_LEN + + IP_HEADER_LEN || pkt->buffer->size >= ETH_HEADER_LEN + + MPLS_HEADER_LEN + IPV6_HEADER_LEN) { + // Assumes an IPv4 or Ipv6 header follows, if there is place for it + uint8_t version = *((uint8_t *)mpls + MPLS_HEADER_LEN) >> 4; + if (version == IPV4_VERSION){ + struct ip_header *ipv4 = (struct ip_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); + mpls->fields = (mpls->fields & ~htonl(MPLS_TTL_MASK)) | htonl((uint32_t)ipv4->ip_ttl & MPLS_TTL_MASK); + } + else if (version == IPV6_VERSION){ + struct ipv6_header *ipv6 = (struct ipv6_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); + mpls->fields = (mpls->fields & ~htonl(MPLS_TTL_MASK)) | htonl((uint32_t)ipv6->ipv6_hop_limit & MPLS_TTL_MASK); + } + } + else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute copy ttl in action on packet with only one mpls."); } } else { @@ -400,17 +406,26 @@ copy_ttl_in(struct packet *pkt, struct ofl_action_header *act UNUSED) { in_mpls->fields = (in_mpls->fields & ~htonl(MPLS_TTL_MASK)) | (mpls->fields & htonl(MPLS_TTL_MASK)); - } else if (pkt->buffer->size >= ETH_HEADER_LEN + MPLS_HEADER_LEN + IP_HEADER_LEN) { - // Assumes an IPv4 header follows, if there is place for it - struct ip_header *ipv4 = (struct ip_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); - - uint8_t new_ttl = (ntohl(mpls->fields) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT; - uint16_t old_val = htons((ipv4->ip_proto) + (ipv4->ip_ttl<<8)); - uint16_t new_val = htons((ipv4->ip_proto) + (new_ttl<<8)); - ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); - ipv4->ip_ttl = new_ttl; - - } else { + } else if (pkt->buffer->size >= ETH_HEADER_LEN + MPLS_HEADER_LEN + + IP_HEADER_LEN || pkt->buffer->size >= ETH_HEADER_LEN + + MPLS_HEADER_LEN + IPV6_HEADER_LEN) { + // Assumes an IPv4 or Ipv6 header follows, if there is place for it + uint8_t version = *((uint8_t *)mpls + MPLS_HEADER_LEN) >> 4; + if (version == IPV4_VERSION){ + struct ip_header *ipv4 = (struct ip_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); + uint8_t new_ttl = (ntohl(mpls->fields) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT; + uint16_t old_val = htons((ipv4->ip_proto) + (ipv4->ip_ttl<<8)); + uint16_t new_val = htons((ipv4->ip_proto) + (new_ttl<<8)); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_ttl = new_ttl; + } + else if (version == IPV6_VERSION){ + struct ipv6_header *ipv6 = (struct ipv6_header *)((uint8_t *)mpls + MPLS_HEADER_LEN); + uint8_t new_ttl = (ntohl(mpls->fields) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT; + ipv6->ipv6_hop_limit = new_ttl; + } + } + else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute copy ttl in action on packet with only one mpls."); } } else { From 583e20b2388e43acddb96ab23f6a9059fbc49851 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Sat, 6 Sep 2014 23:14:54 -0300 Subject: [PATCH 071/191] Add checks for bad wildcarded flows. This commit add functions to check if a masked field is valid. --- oflib/oxm-match.c | 109 +++++++++++++++++++++++++++++++++++++++++----- oflib/oxm-match.h | 18 ++++++++ 2 files changed, 117 insertions(+), 10 deletions(-) diff --git a/oflib/oxm-match.c b/oflib/oxm-match.c index 0d4fc4e9..b1da8c3f 100644 --- a/oflib/oxm-match.c +++ b/oflib/oxm-match.c @@ -110,6 +110,65 @@ oxm_init(void) } } +bool +check_bad_wildcard(uint8_t value, uint8_t mask){ + uint8_t masked = value & mask; + if (value == masked){ + return false; + } + else { + return true; + } +} + +bool +check_bad_wildcard16(uint16_t value, uint16_t mask){ + uint16_t masked = value & mask; + if (value == masked){ + return false; + } + else { + return true; + } +} + +bool +check_bad_wildcard32(uint32_t value, uint32_t mask){ + uint32_t masked = value & mask; + if (value == masked){ + return false; + } + else { + return true; + } +} + +bool +check_bad_wildcard48(uint8_t *value, uint8_t *mask){ + return (check_bad_wildcard16(*((uint16_t *) value), *((uint16_t *) mask)) || + check_bad_wildcard32(*((uint32_t *) (value + 2)), + *((uint32_t *) (mask + 2)))); +} + +bool +check_bad_wildcard64(uint64_t value, uint64_t mask){ + uint64_t masked = value & mask; + if (value == masked){ + return false; + } + else { + return true; + } +} + +bool +check_bad_wildcard128(uint8_t *value, uint8_t *mask){ + return (check_bad_wildcard64(*((uint64_t *) value), *((uint64_t *) mask)) || + check_bad_wildcard64(*((uint64_t *) (value + 8)), + *((uint64_t *) (mask + 8)))); +} + + struct oxm_field * oxm_field_lookup(uint32_t header) { @@ -266,6 +325,9 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, return 0; } case OFI_OXM_OF_METADATA_W:{ + if (check_bad_wildcard64(ntoh64(*((uint64_t*) value)), ntoh64(*((uint64_t*) mask)))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put64m(match, f->header, ntoh64(*((uint64_t*) value)), ntoh64(*((uint64_t*) mask))); return 0; } @@ -277,6 +339,9 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, } case OFI_OXM_OF_ETH_DST_W: case OFI_OXM_OF_ETH_SRC_W:{ + if (check_bad_wildcard48((uint8_t* )value, (uint8_t* )mask)){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put_eth_m(match, f->header,(uint8_t* )value, (uint8_t* )mask ); return 0; } @@ -300,6 +365,10 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, uint16_t* vlan_id = (uint16_t*) value; uint16_t* vlan_mask = (uint16_t*) mask; + if (check_bad_wildcard16(ntohs(*vlan_id), ntohs(*vlan_mask))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } + if (ntohs(*vlan_id) > OFPVID_PRESENT+VLAN_VID_MAX) return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_VALUE); else @@ -342,25 +411,33 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, case OFI_OXM_OF_IPV4_SRC: case OFI_OXM_OF_IPV4_DST: case OFI_OXM_OF_ARP_TPA: - case OFI_OXM_OF_ARP_SPA: + case OFI_OXM_OF_ARP_SPA:{ ofl_structs_match_put32(match, f->header, *((uint32_t*) value)); return 0; + } case OFI_OXM_OF_IPV4_DST_W: case OFI_OXM_OF_IPV4_SRC_W: case OFI_OXM_OF_ARP_SPA_W: - case OFI_OXM_OF_ARP_TPA_W: - ofl_structs_match_put32m(match, f->header, *((uint32_t*) value), *((uint32_t*) mask)); - return 0; + case OFI_OXM_OF_ARP_TPA_W:{ + if (check_bad_wildcard32(*((uint32_t*) value), *((uint32_t*) mask))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } + ofl_structs_match_put32m(match, f->header, *((uint32_t*) value), *((uint32_t*) mask)); + return 0; + } case OFI_OXM_OF_ARP_SHA: case OFI_OXM_OF_ARP_THA: ofl_structs_match_put_eth(match, f->header,(uint8_t* )value); return 0; case OFI_OXM_OF_ARP_SHA_W: - case OFI_OXM_OF_ARP_THA_W: + case OFI_OXM_OF_ARP_THA_W:{ + if (check_bad_wildcard48((uint8_t* )value, (uint8_t* )mask)){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put_eth_m(match, f->header,(uint8_t* )value, (uint8_t* )mask ); return 0; - + } /* IPv6 addresses. */ case OFI_OXM_OF_IPV6_SRC: case OFI_OXM_OF_IPV6_DST:{ @@ -369,6 +446,9 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, } case OFI_OXM_OF_IPV6_SRC_W: case OFI_OXM_OF_IPV6_DST_W:{ + if (check_bad_wildcard128((uint8_t* ) value,(uint8_t* ) mask)){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put_ipv6m(match, f->header,(uint8_t* ) value,(uint8_t* ) mask); return 0; } @@ -377,6 +457,9 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, return 0; } case OFI_OXM_OF_IPV6_FLABEL_W:{ + if (check_bad_wildcard32(*((uint32_t*) value), *((uint32_t*) mask))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put32m(match, f->header, ntohl(*((uint32_t*) value)), ntohl(*((uint32_t*) mask))); return 0; } @@ -391,7 +474,6 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, case OFI_OXM_OF_SCTP_DST: ofl_structs_match_put16(match, f->header, ntohs(*((uint16_t*) value))); return 0; - /* ICMP header. */ case OFI_OXM_OF_ICMPV4_TYPE: case OFI_OXM_OF_ICMPV4_CODE: @@ -431,14 +513,21 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, case OFI_OXM_OF_PBB_ISID: ofl_structs_match_put32(match, f->header, ntohl(*((uint32_t*) value))); return 0; - case OFI_OXM_OF_PBB_ISID_W: - ofl_structs_match_put32m(match, f->header, ntohl(*((uint32_t*) value)), ntohl(*((uint32_t*) mask))); - return 0; + case OFI_OXM_OF_PBB_ISID_W:{ + if (check_bad_wildcard32(*((uint32_t*) value), *((uint32_t*) mask))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } + ofl_structs_match_put32m(match, f->header, ntohl(*((uint32_t*) value)), ntohl(*((uint32_t*) mask))); + return 0; + } case OFI_OXM_OF_TUNNEL_ID:{ ofl_structs_match_put64(match, f->header, *((uint64_t*) value)); return 0; } case OFI_OXM_OF_TUNNEL_ID_W:{ + if (check_bad_wildcard64(*((uint64_t*) value), *((uint64_t*) mask))){ + return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); + } ofl_structs_match_put64m(match, f->header,*((uint64_t*) value),*((uint64_t*) mask)); return 0; } diff --git a/oflib/oxm-match.h b/oflib/oxm-match.h index f870f175..0e4fde00 100644 --- a/oflib/oxm-match.h +++ b/oflib/oxm-match.h @@ -299,6 +299,24 @@ struct oxm_field { /* All the known fields. */ extern struct oxm_field all_fields[NUM_OXM_FIELDS]; +bool +check_bad_wildcard(uint8_t value, uint8_t mask); + +bool +check_bad_wildcard16(uint16_t value, uint16_t mask); + +bool +check_bad_wildcard32(uint32_t value, uint32_t mask); + +bool +check_bad_wildcard48(uint8_t *value, uint8_t *mask); + +bool +check_bad_wildcard64(uint64_t value, uint64_t mask); + +bool +check_bad_wildcard128(uint8_t *value, uint8_t *mask); + struct oxm_field * oxm_field_lookup(uint32_t header); From f2ab22481a97d2178f54db9af0d4255d134f5763 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Sat, 6 Sep 2014 23:19:04 -0300 Subject: [PATCH 072/191] Fix some match errors - Fix error while matching masked IPv6, IPv4 and ethernet addresses. - Fix default metadata value. The older value was leading to wrong flow misses. --- udatapath/match_std.c | 26 ++++++++++++-------------- udatapath/packet_handle_std.c | 6 +++--- udatapath/pipeline.c | 2 +- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 54226293..201ddaaa 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -35,6 +35,10 @@ #include "oflib/oxm-match.h" #include "match_std.h" + +#include "vlog.h" +#define LOG_MODULE VLM_flow_e + /* Returns true if two 8 bit values match */ static inline bool match_8(uint8_t *a, uint8_t *b) { @@ -60,9 +64,8 @@ static inline bool match_mask16(uint8_t *a, uint8_t *am, uint8_t *b) { uint16_t *a1 = (uint16_t *) a; uint16_t *b1 = (uint16_t *) b; - uint16_t *mask = (uint16_t *) am; - - return (((~*mask) & (*a1 ^ *b1)) == 0); + uint16_t mask = (uint16_t) ((uint8_t) ~am[0] << 8 | (uint8_t) ~a[1]); + return (((mask) & (*a1 ^ *b1)) == 0); } /* Returns true if two 32 bit values match */ @@ -70,7 +73,6 @@ static inline bool match_32(uint8_t *a, uint8_t *b) { uint32_t *a1 = (uint32_t *) a; uint32_t *b1 = (uint32_t *) b; - return (*a1 == *b1); } @@ -79,9 +81,9 @@ static inline bool match_mask32(uint8_t *a, uint8_t *am, uint8_t *b) { uint32_t *a1 = (uint32_t *) a; uint32_t *b1 = (uint32_t *) b; - uint32_t *mask = (uint32_t *) am; - - return (((~*mask) & (*a1 ^ *b1)) == 0); + uint32_t mask = (uint32_t) ((uint8_t) ~am[0] << 24 | (uint8_t) ~am[1] << 16 + | (uint8_t) ~am[2] << 8 | (uint8_t) ~am[3]); + return (((mask) & (*a1 ^ *b1)) == 0); } /* Returns true if two 48 bit values match */ @@ -103,7 +105,7 @@ static inline bool match_64(uint8_t *a, uint8_t *b) { uint64_t *a1 = (uint64_t *) a; uint64_t *b1 = (uint64_t *) b; - + VLOG_ERR(LOG_MODULE, "Result %"PRIx64" %"PRIx64"", *a1, *b1); return (*a1 == *b1); } @@ -112,9 +114,8 @@ static inline bool match_mask64(uint8_t *a, uint8_t *am, uint8_t *b) { uint64_t *a1 = (uint64_t *) a; uint64_t *b1 = (uint64_t *) b; - uint64_t *mask = (uint64_t *) am; - - return (((~*mask) & (*a1 ^ *b1)) == 0); + uint64_t mask = *((uint64_t*) am); + return (((mask) & (*a1 ^ *b1)) == 0); } /* Returns true if two 128 bit values match */ @@ -164,9 +165,6 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ flow_mask = f->value + field_len; } - char *f_str = ofl_structs_oxm_tlv_to_string(f); - free(f_str); - /* Lookup the packet header */ packet_f = oxm_match_lookup(packet_header, packet); if (!packet_f) { diff --git a/udatapath/packet_handle_std.c b/udatapath/packet_handle_std.c index 1a75df3e..04c90174 100644 --- a/udatapath/packet_handle_std.c +++ b/udatapath/packet_handle_std.c @@ -49,10 +49,10 @@ void packet_handle_std_validate(struct packet_handle_std *handle) { - + struct ofl_match_tlv * iter, *next; if(handle->valid) return; - struct ofl_match_tlv * iter, *next; + HMAP_FOR_EACH_SAFE(iter, next, struct ofl_match_tlv, hmap_node, &handle->match.match_fields){ free(iter->value); free(iter); @@ -68,7 +68,7 @@ packet_handle_std_validate(struct packet_handle_std *handle) { /* Add in_port value to the hash_map */ ofl_structs_match_put32(&handle->match, OXM_OF_IN_PORT, handle->pkt->in_port); /*Add metadata value to the hash_map */ - ofl_structs_match_put64(&handle->match, OXM_OF_METADATA, 0xffffffffffffffff); + ofl_structs_match_put64(&handle->match, OXM_OF_METADATA, 0x0000000000000000); return; } diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index 1388a955..6e01d1e0 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -616,7 +616,7 @@ execute_entry(struct pipeline *pl, struct flow_entry *entry, hmap_node, hash_int(OXM_OF_METADATA,0), &(*pkt)->handle_std->match.match_fields){ uint64_t *metadata = (uint64_t*) f->value; *metadata = (*metadata & ~wi->metadata_mask) | (wi->metadata & wi->metadata_mask); - VLOG_DBG_RL(LOG_MODULE, &rl, "Executing write metadata: %"PRIu64"", *metadata); + VLOG_DBG_RL(LOG_MODULE, &rl, "Executing write metadata: %"PRIx64"", *metadata); } break; } From 0b82d220fdd20f81849bf266aecea94108d95ad5 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Sun, 7 Sep 2014 09:23:19 -0300 Subject: [PATCH 073/191] Implement SET_NW_TTL and DEC_NW_TTL for IPv6 packets The implementation of SET_NW_TTL and DEC_NW_TTL was not considering IPv6 packets. This commit fix this, setting and decrementing the ipv6 hop_limit on respective action. --- udatapath/dp_actions.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 316c3575..3e7d926f 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -636,7 +636,7 @@ push_mpls(struct packet *pkt, struct ofl_action_push *act) { new_ipv4 = ipv4 == NULL ? NULL : (struct ip_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); new_ipv6 = ipv6 == NULL ? NULL - : (struct ip_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); + : (struct ipv6_header *)((uint8_t *)push_mpls + MPLS_HEADER_LEN); } if (new_mpls != NULL) { @@ -835,8 +835,12 @@ set_nw_ttl(struct packet *pkt, struct ofl_action_set_nw_ttl *act) { uint16_t new_val = htons((ipv4->ip_proto) + (act->nw_ttl<<8)); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); ipv4->ip_ttl = act->nw_ttl; - } else { - VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_NW_TTL action on packet with no ipv4."); + } else if (pkt->handle_std->proto->ipv6 != NULL){ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + ipv6->ipv6_hop_limit = act->nw_ttl; + } + else { + VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute SET_NW_TTL action on packet with no ipv4 or ipv6."); } } @@ -856,7 +860,13 @@ dec_nw_ttl(struct packet *pkt, struct ofl_action_header *act UNUSED) { ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); ipv4->ip_ttl = new_ttl; } - } else { + } else if (pkt->handle_std->proto->ipv6 != NULL){ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + if (ipv6->ipv6_hop_limit > 0){ + --ipv6->ipv6_hop_limit; + } + } + else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute DEC_NW_TTL action on packet with no ipv4."); } } From 336502f3e8e14de678e8e3ee9fe8a833daadd3c6 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Mon, 8 Sep 2014 22:59:18 -0300 Subject: [PATCH 074/191] Fix OXM_OF_IPV6_ND_SLL and OXM_OF_IPV6_ND_TLL set_field action. This commit fix set_field action of IPv6 Neighbor Discovery TLL and SLL, correcting the value memcpy position and recalculating the ICMPv6 checksum. --- udatapath/dp_actions.c | 46 +++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 3e7d926f..6337be87 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -139,7 +139,14 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) break; } case OXM_OF_IP_PROTO:{ - pkt->handle_std->proto->ipv4->ip_proto = *act->field->value; + struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; + uint16_t new_val, old_val; + uint8_t proto = *act->field->value; + old_val = htons((ipv4->ip_ttl << 8) + ipv4->ip_proto); + VLOG_ERR(LOG_MODULE, "Proto %d %d", ipv4->ip_proto, proto); + new_val = htons((ipv4->ip_ttl << 8) + proto); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_proto = proto; break; } case OXM_OF_IPV4_SRC:{ @@ -294,34 +301,31 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) OXM_LENGTH(act->field->header)); break; } - case OXM_OF_IPV6_ND_SLL:{ - struct icmp_header *icmp = pkt->handle_std->proto->icmp; - uint8_t offset; - struct ipv6_nd_options_hd *opt = (struct ipv6_nd_options_hd*) - icmp + sizeof(struct icmp_header); - uint8_t *data = (uint8_t*) opt; - /*ICMP header + neighbor discovery header reserverd bytes*/ - offset = sizeof(struct ipv6_nd_header); - - if(opt->type == ND_OPT_SLL){ - memcpy(data + offset, act->field->value, - OXM_LENGTH(act->field->header)); - } - break; - } + case OXM_OF_IPV6_ND_SLL: case OXM_OF_IPV6_ND_TLL:{ struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; + uint32_t old_val32; + uint32_t new_val32; + uint16_t old_val16; + uint16_t new_val16; struct ipv6_nd_options_hd *opt = (struct ipv6_nd_options_hd*) - icmp + sizeof(struct icmp_header); + ((uint8_t*) icmp + sizeof(struct icmp_header) + + sizeof(struct ipv6_nd_header)); uint8_t *data = (uint8_t*) opt; - /*ICMP header + neighbor discovery header reserverd bytes*/ - offset = sizeof(struct ipv6_nd_header); + /*ICMP header + neighbor discovery header reserved bytes*/ + offset = sizeof(struct ipv6_nd_options_hd); + if(opt->type == ND_OPT_SLL || opt->type == ND_OPT_TLL){ + old_val16 = *((uint16_t*) (data + offset)); + old_val32 = *((uint32_t*) (data + offset + sizeof(uint16_t))); - if(opt->type == ND_OPT_TLL){ memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); - } + new_val16 = *((uint16_t*) (act->field->value)); + new_val32 = *((uint32_t*) (act->field->value + sizeof(uint16_t))); + icmp->icmp_csum = recalc_csum16(icmp->icmp_csum, old_val16, new_val16); + icmp->icmp_csum = recalc_csum32(icmp->icmp_csum, old_val32, new_val32); + } break; } case OXM_OF_MPLS_LABEL:{ From 064980000fe57e5b502e554d36dc75d393a7cc1d Mon Sep 17 00:00:00 2001 From: oftutorial Date: Tue, 7 Oct 2014 22:29:43 -0300 Subject: [PATCH 075/191] Fix potential bug in handling metadata. In a OFPIT_WRITE_METADATA the value would be reset, as pointed by Jean Tourrilhes. This commit fix this behavior and also add tunnel metadata information to the packet parsing. --- udatapath/packet_handle_std.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/udatapath/packet_handle_std.c b/udatapath/packet_handle_std.c index 04c90174..62a322f3 100644 --- a/udatapath/packet_handle_std.c +++ b/udatapath/packet_handle_std.c @@ -49,10 +49,22 @@ void packet_handle_std_validate(struct packet_handle_std *handle) { - struct ofl_match_tlv * iter, *next; + struct ofl_match_tlv * iter, *next, *f; + uint64_t metadata = 0; + uint64_t tunnel_id = 0; if(handle->valid) return; + HMAP_FOR_EACH_WITH_HASH(f, struct ofl_match_tlv, + hmap_node, hash_int(OXM_OF_METADATA,0), &handle->match.match_fields){ + metadata = *((uint64_t*) f->value); + } + + HMAP_FOR_EACH_WITH_HASH(f, struct ofl_match_tlv, + hmap_node, hash_int(OXM_OF_METADATA,0), &handle->match.match_fields){ + tunnel_id = *((uint64_t*) f->value); + } + HMAP_FOR_EACH_SAFE(iter, next, struct ofl_match_tlv, hmap_node, &handle->match.match_fields){ free(iter->value); free(iter); @@ -67,8 +79,9 @@ packet_handle_std_validate(struct packet_handle_std *handle) { /* Add in_port value to the hash_map */ ofl_structs_match_put32(&handle->match, OXM_OF_IN_PORT, handle->pkt->in_port); - /*Add metadata value to the hash_map */ - ofl_structs_match_put64(&handle->match, OXM_OF_METADATA, 0x0000000000000000); + /*Add metadata and tunnel_id value to the hash_map */ + ofl_structs_match_put64(&handle->match, OXM_OF_METADATA, metadata); + ofl_structs_match_put64(&handle->match, OXM_OF_TUNNEL_ID, tunnel_id); return; } From 8f9cad4f072f0cd1897bb88bfdb0ff6d197194d8 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Tue, 7 Oct 2014 23:59:36 -0300 Subject: [PATCH 076/191] Fix IPv4 checksum on IPv4 ECN or DSCP set field This commit updates the IPv4 packet checksum after changing the DSCP or ECN fields. Furthermore, it add the case of setting IPv6 DSCP and ECN. --- lib/packets.h | 8 +++++++- udatapath/dp_actions.c | 44 ++++++++++++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/lib/packets.h b/lib/packets.h index b92aa7f2..c4ca42e8 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -259,7 +259,11 @@ BUILD_ASSERT_DECL(IP_HEADER_LEN == sizeof(struct ip_header)); #define IPV6_FLABEL(ipv6_ver_tc_fl) ((ipv6_ver_tc_fl) & 0xffff) #define IPV6_VERSION 6 -#define IPV6_FLABEL_MASK 0xfffff +#define IPV6_DSCP_MASK 0x0fc00000 +#define IPV6_DSCP_SHIFT 22 +#define IPV6_ECN_MASK 0x00300000 +#define IPV6_ECN_SHIFT 20 +#define IPV6_FLABEL_MASK 0x000fffff #define IPV6_HEADER_LEN 40 struct ipv6_header { uint32_t ipv6_ver_tc_fl; @@ -300,12 +304,14 @@ struct ipv6_nd_header{ uint32_t reserved; struct in6_addr target_addr; }; +BUILD_ASSERT_DECL(IPV6_ND_HEADER_LEN == sizeof(struct ipv6_nd_header)); #define IPV6_ND_OPT_HD_LEN 2 struct ipv6_nd_options_hd{ uint8_t type; uint8_t length; }; +BUILD_ASSERT_DECL(IPV6_ND_OPT_HD_LEN == sizeof(struct ipv6_nd_options_hd)); #define UDP_HEADER_LEN 8 struct udp_header { diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 6337be87..fa67bdb0 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -119,24 +119,40 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) } } case OXM_OF_IP_DSCP:{ - struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; - uint8_t tos = (ipv4->ip_tos & ~IP_DSCP_MASK) | - (*act->field->value << 2); - uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); - uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + tos); - ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); - ipv4->ip_tos = tos; + if (pkt->handle_std->proto->ipv4){ + struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; + uint8_t tos = (ipv4->ip_tos & ~IP_DSCP_MASK) | + (*act->field->value << 2); + uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); + uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + tos); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_tos = tos; + } + else if (pkt->handle_std->proto->ipv6){ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + uint32_t ipv6_ver_tc_fl = (ipv6->ipv6_ver_tc_fl & ~htonl(IPV6_DSCP_MASK)) | + htonl((((uint32_t) *act->field->value) << IPV6_DSCP_SHIFT)); + ipv6->ipv6_ver_tc_fl = ipv6_ver_tc_fl; + } break; } case OXM_OF_IP_ECN:{ - struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; - uint8_t tos = (ipv4->ip_tos & ~IP_ECN_MASK) | + if (pkt->handle_std->proto->ipv4){ + struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; + uint8_t tos = (ipv4->ip_tos & ~IP_ECN_MASK) | (*act->field->value & IP_ECN_MASK); - uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); - uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + tos); - ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); - ipv4->ip_tos = tos; - break; + uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); + uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + tos); + ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); + ipv4->ip_tos = tos; + } + else if (pkt->handle_std->proto->ipv6){ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + uint32_t ipv6_ver_tc_fl = (ipv6->ipv6_ver_tc_fl & ~htonl(IPV6_ECN_MASK)) | + htonl((((uint32_t) *act->field->value) << IPV6_ECN_SHIFT)); + ipv6->ipv6_ver_tc_fl = ipv6_ver_tc_fl; + } + break; } case OXM_OF_IP_PROTO:{ struct ip_header *ipv4 = pkt->handle_std->proto->ipv4; From a0fed8b7084636b633d0d973d76d4da46b539b0d Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 29 Sep 2014 14:39:43 -0700 Subject: [PATCH 077/191] Always clone packet with an empty action-set. Fix a bug where if an action-list invoke a group, the current action-set leaks into the execution of the group bucket. --- udatapath/action_set.c | 4 +++- udatapath/dp_actions.c | 5 +++++ udatapath/group_entry.c | 3 +++ udatapath/packet.c | 7 ++++++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/udatapath/action_set.c b/udatapath/action_set.c index 43c1ec6d..d63f5017 100644 --- a/udatapath/action_set.c +++ b/udatapath/action_set.c @@ -218,7 +218,9 @@ action_set_execute(struct action_set *set, struct packet *pkt, uint64_t cookie) uint32_t group_id = pkt->out_group; pkt->out_group = OFPG_ANY; - action_set_clear_actions(pkt->action_set); + /* We don't need to clear the action-set because group will clone + * the packet with an empty action-set. Jean II + * action_set_clear_actions(pkt->action_set); */ group_table_execute(pkt->dp->groups, pkt, group_id); return; diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index fa67bdb0..4faf9743 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -1000,6 +1000,11 @@ dp_execute_action_list(struct packet *pkt, uint32_t group = pkt->out_group; pkt->out_group = OFPG_ANY; VLOG_DBG_RL(LOG_MODULE, &rl, "Group action; executing group (%u).", group); + /* The group must process a copy of the packet in the current state, + * so that when we return we continue processing an unmodified + * version of the packet. The group must also ignore the current + * action-set. Group functions will clone the packet with an + * empty action-set. Jean II */ group_table_execute(pkt->dp->groups, pkt, group); } else if (pkt->out_port != OFPP_ANY) { diff --git a/udatapath/group_entry.c b/udatapath/group_entry.c index 399baa11..b5de2172 100644 --- a/udatapath/group_entry.c +++ b/udatapath/group_entry.c @@ -283,6 +283,9 @@ group_entry_execute(struct group_entry *entry, /* NOTE: Packet is copied for all buckets now (even if there is only one). * This allows execution of the original packet onward. It is not clear * whether that is allowed or not according to the spec. though. */ + /* Spec v1.1 and later say that group can occur in action-list, it must + * process a copy of the packet and execution continue on the original + * packet. Jean II */ switch (entry->desc->type) { case (OFPGT_ALL): { diff --git a/udatapath/packet.c b/udatapath/packet.c index 0ab614a9..5911f342 100644 --- a/udatapath/packet.c +++ b/udatapath/packet.c @@ -75,7 +75,12 @@ packet_clone(struct packet *pkt) { clone->dp = pkt->dp; clone->buffer = ofpbuf_clone(pkt->buffer); clone->in_port = pkt->in_port; - clone->action_set = action_set_clone(pkt->action_set); + /* There is no case we need to keep the action-set, but if it's needed + * we could add a parameter to the function... Jean II + * clone->action_set = action_set_clone(pkt->action_set); + */ + clone->action_set = action_set_create(pkt->dp->exp); + clone->packet_out = pkt->packet_out; clone->out_group = OFPG_ANY; From 3b28f740b8087896610072cfb36e20929f663cd9 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Fri, 3 Oct 2014 15:40:26 -0700 Subject: [PATCH 078/191] Break long string in flow stat reply for readability. --- oflib/ofl-messages-print.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oflib/ofl-messages-print.c b/oflib/ofl-messages-print.c index 4b6c1e34..56dd96b5 100644 --- a/oflib/ofl-messages-print.c +++ b/oflib/ofl-messages-print.c @@ -382,7 +382,7 @@ ofl_msg_print_stats_reply_flow(struct ofl_msg_multipart_reply_flow *msg, FILE *s for (i=0; istats_num; i++) { ofl_structs_flow_stats_print(stream, msg->stats[i], exp); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); From 98386c95358cdb7e0067e009d1978f7df49bfb25 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Wed, 1 Oct 2014 14:52:23 -0700 Subject: [PATCH 079/191] Change packet ownership strategy to avoid cloning packet in groups. --- udatapath/action_set.c | 15 ++++++++---- udatapath/dp_actions.c | 8 ++++--- udatapath/group_entry.c | 53 ++++++++++++++++++++++------------------- udatapath/pipeline.c | 3 ++- 4 files changed, 46 insertions(+), 33 deletions(-) diff --git a/udatapath/action_set.c b/udatapath/action_set.c index d63f5017..a72ec6df 100644 --- a/udatapath/action_set.c +++ b/udatapath/action_set.c @@ -211,6 +211,11 @@ action_set_execute(struct action_set *set, struct packet *pkt, uint64_t cookie) dp_execute_action(pkt, entry->action); list_remove(&entry->node); free(entry); + } + + /* Clear the action set in any case. Group processing depend on + * a clean action-set. Jean II */ + action_set_clear_actions(pkt->action_set); /* According to the spec. if there was a group action, the output * port action should be ignored */ @@ -218,9 +223,7 @@ action_set_execute(struct action_set *set, struct packet *pkt, uint64_t cookie) uint32_t group_id = pkt->out_group; pkt->out_group = OFPG_ANY; - /* We don't need to clear the action-set because group will clone - * the packet with an empty action-set. Jean II - * action_set_clear_actions(pkt->action_set); */ + /* Transfer packet to the group. It will be destroyed. Jean II */ group_table_execute(pkt->dp->groups, pkt, group_id); return; @@ -232,11 +235,13 @@ action_set_execute(struct action_set *set, struct packet *pkt, uint64_t cookie) pkt->out_port_max_len = 0; pkt->out_queue = 0; - action_set_clear_actions(pkt->action_set); dp_actions_output_port(pkt, port_id, queue_id, max_len, cookie); + packet_destroy(pkt); return; } - } + + /* No output or group action. Just drop the packet. Jean II */ + packet_destroy(pkt); } char * diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 4faf9743..99ab5e56 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -997,15 +997,17 @@ dp_execute_action_list(struct packet *pkt, dp_execute_action(pkt, actions[i]); if (pkt->out_group != OFPG_ANY) { + struct packet *pkt_clone; uint32_t group = pkt->out_group; pkt->out_group = OFPG_ANY; VLOG_DBG_RL(LOG_MODULE, &rl, "Group action; executing group (%u).", group); /* The group must process a copy of the packet in the current state, * so that when we return we continue processing an unmodified * version of the packet. The group must also ignore the current - * action-set. Group functions will clone the packet with an - * empty action-set. Jean II */ - group_table_execute(pkt->dp->groups, pkt, group); + * action-set. We need to clone the packet with an empty + * action-set. Jean II */ + pkt_clone = packet_clone(pkt); + group_table_execute(pkt_clone->dp->groups, pkt_clone, group); } else if (pkt->out_port != OFPP_ANY) { uint32_t port = pkt->out_port; diff --git a/udatapath/group_entry.c b/udatapath/group_entry.c index b5de2172..fd3ce8ac 100644 --- a/udatapath/group_entry.c +++ b/udatapath/group_entry.c @@ -178,6 +178,7 @@ execute_all(struct group_entry *entry, struct packet *pkt) { packet_destroy(p); } + packet_destroy(pkt); } /* Executes a group entry of type SELECT. */ @@ -187,7 +188,6 @@ execute_select(struct group_entry *entry, struct packet *pkt) { if (b != -1) { struct ofl_bucket *bucket = entry->desc->buckets[b]; - struct packet *p = packet_clone(pkt); if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *b = ofl_structs_bucket_to_string(bucket, entry->dp->exp); @@ -195,19 +195,19 @@ execute_select(struct group_entry *entry, struct packet *pkt) { free(b); } - action_set_write_actions(p->action_set, bucket->actions_num, bucket->actions); + action_set_write_actions(pkt->action_set, bucket->actions_num, bucket->actions); - entry->stats->byte_count += p->buffer->size; + entry->stats->byte_count += pkt->buffer->size; entry->stats->packet_count++; - entry->stats->counters[b]->byte_count += p->buffer->size; + entry->stats->counters[b]->byte_count += pkt->buffer->size; entry->stats->counters[b]->packet_count++; /* Cookie field is set 0xffffffffffffffff because we cannot associate to any particular flow */ - action_set_execute(p->action_set, p, 0xffffffffffffffff); - packet_destroy(p); + action_set_execute(pkt->action_set, pkt, 0xffffffffffffffff); } else { VLOG_DBG_RL(LOG_MODULE, &rl, "No bucket in group."); + packet_destroy(pkt); } } @@ -217,7 +217,6 @@ execute_indirect(struct group_entry *entry, struct packet *pkt) { if (entry->desc->buckets_num > 0) { struct ofl_bucket *bucket = entry->desc->buckets[0]; - struct packet *p = packet_clone(pkt); if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *b = ofl_structs_bucket_to_string(bucket, entry->dp->exp); @@ -225,19 +224,19 @@ execute_indirect(struct group_entry *entry, struct packet *pkt) { free(b); } - action_set_write_actions(p->action_set, bucket->actions_num, bucket->actions); + action_set_write_actions(pkt->action_set, bucket->actions_num, bucket->actions); - entry->stats->byte_count += p->buffer->size; + entry->stats->byte_count += pkt->buffer->size; entry->stats->packet_count++; - entry->stats->counters[0]->byte_count += p->buffer->size; + entry->stats->counters[0]->byte_count += pkt->buffer->size; entry->stats->counters[0]->packet_count++; /* Cookie field is set 0xffffffffffffffff because we cannot associate to any particular flow */ - action_set_execute(p->action_set, p, 0xffffffffffffffff); - packet_destroy(p); + action_set_execute(pkt->action_set, pkt, 0xffffffffffffffff); } else { VLOG_DBG_RL(LOG_MODULE, &rl, "No bucket in group."); + packet_destroy(pkt); } } @@ -248,7 +247,6 @@ execute_ff(struct group_entry *entry, struct packet *pkt) { if (b != -1) { struct ofl_bucket *bucket = entry->desc->buckets[b]; - struct packet *p = packet_clone(pkt); if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *b = ofl_structs_bucket_to_string(bucket, entry->dp->exp); @@ -256,19 +254,19 @@ execute_ff(struct group_entry *entry, struct packet *pkt) { free(b); } - action_set_write_actions(p->action_set, bucket->actions_num, bucket->actions); + action_set_write_actions(pkt->action_set, bucket->actions_num, bucket->actions); - entry->stats->byte_count += p->buffer->size; + entry->stats->byte_count += pkt->buffer->size; entry->stats->packet_count++; - entry->stats->counters[b]->byte_count += p->buffer->size; + entry->stats->counters[b]->byte_count += pkt->buffer->size; entry->stats->counters[b]->packet_count++; /* Cookie field is set 0xffffffffffffffff because we cannot associate to any particular flow */ - action_set_execute(p->action_set, p, 0xffffffffffffffff); - packet_destroy(p); + action_set_execute(pkt->action_set, pkt, 0xffffffffffffffff); } else { VLOG_DBG_RL(LOG_MODULE, &rl, "No bucket in group."); + packet_destroy(pkt); } } @@ -280,12 +278,18 @@ group_entry_execute(struct group_entry *entry, VLOG_DBG_RL(LOG_MODULE, &rl, "Executing group %u.", entry->stats->group_id); - /* NOTE: Packet is copied for all buckets now (even if there is only one). - * This allows execution of the original packet onward. It is not clear - * whether that is allowed or not according to the spec. though. */ - /* Spec v1.1 and later say that group can occur in action-list, it must - * process a copy of the packet and execution continue on the original - * packet. Jean II */ + /* Group action are often used in the action-set. Action-set + * processing is terminal, so the original packet is passed to us + * for processing. In that case, the caller must clear the + * action-set of the packet. See action_set_execute(). + * Spec v1.1 and later also say that a group action can occur in + * action-list, in that case it must process a clone/copy of the + * packet and execution continue on the original packet. In that + * case, the caller must do the appropriate cloning of the packet. + * See dp_execute_action_list(). + * In any case, we won't return the packet to the caller, we will + * destroy it or pass it to someone. + * Jean II */ switch (entry->desc->type) { case (OFPGT_ALL): { @@ -306,6 +310,7 @@ group_entry_execute(struct group_entry *entry, } default: { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to execute unknown group type (%u) in group (%u).", entry->desc->type, entry->stats->group_id); + packet_destroy(packet); } } } diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index 6e01d1e0..6960bac1 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -118,6 +118,8 @@ send_packet_to_controller(struct pipeline *pl, struct packet *pkt, uint8_t table ofl_structs_free_match((struct ofl_match_header* ) m, NULL); } +/* Pass the packet through the flow tables. + * This function takes ownership of the packet and will destroy it. */ void pipeline_process_packet(struct pipeline *pl, struct packet *pkt) { struct flow_table *table, *next_table; @@ -174,7 +176,6 @@ pipeline_process_packet(struct pipeline *pl, struct packet *pkt) { because we cannot associate it to any particular flow */ action_set_execute(pkt->action_set, pkt, 0xffffffffffffffff); - packet_destroy(pkt); return; } From 411c34bc4efdee0964fcf97f67304cbca21c1696 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Wed, 8 Oct 2014 15:39:06 -0700 Subject: [PATCH 080/191] Fix a double free in group of type all with new packet freeing strategy. --- udatapath/group_entry.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/udatapath/group_entry.c b/udatapath/group_entry.c index fd3ce8ac..e61774f8 100644 --- a/udatapath/group_entry.c +++ b/udatapath/group_entry.c @@ -175,8 +175,7 @@ execute_all(struct group_entry *entry, struct packet *pkt) { because we cannot associate to any particular flow */ action_set_execute(p->action_set, p, 0xffffffffffffffff); - - packet_destroy(p); + /* Clone will be destroyed above. Jean II */ } packet_destroy(pkt); } From cddc56266b314e63020f919033f12ef18fda91e5 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Thu, 9 Oct 2014 23:07:09 -0300 Subject: [PATCH 081/191] Add TUNNEL_ID to set_field action. Implements the the tunnel id set_field action, enabling matching on this field after the action. Also fix a little bug when checking if the tunnel_id field value already exists. --- oflib/ofl-actions-pack.c | 2 +- oflib/ofl-actions-unpack.c | 10 +++++----- udatapath/dp_actions.c | 10 +++++++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/oflib/ofl-actions-pack.c b/oflib/ofl-actions-pack.c index ae05dc12..dbdecc29 100644 --- a/oflib/ofl-actions-pack.c +++ b/oflib/ofl-actions-pack.c @@ -227,7 +227,7 @@ ofl_actions_pack(struct ofl_action_header *src, struct ofp_action_header *dst, u break; } case 8:{ - uint64_t value = htons(*((uint64_t*) sa->field->value)); + uint64_t value = hton64(*((uint64_t*) sa->field->value)); memcpy(data + (sizeof(struct ofp_action_set_field)),&value,OXM_LENGTH(sa->field->header)); break; } diff --git a/oflib/ofl-actions-unpack.c b/oflib/ofl-actions-unpack.c index f986e0ca..7e24191a 100644 --- a/oflib/ofl-actions-unpack.c +++ b/oflib/ofl-actions-unpack.c @@ -304,15 +304,15 @@ ofl_actions_unpack(struct ofp_action_header *src, size_t *len, struct ofl_action } case 4:{ uint32_t v; - uint8_t field = OXM_FIELD(da->field->header); - if( field != 11 && field != 12 && field != 22 && field != 23) - v = htonl(*((uint32_t*) value)); - else v = *((uint32_t*) value); + uint8_t field = OXM_FIELD(da->field->header); + if( field != 11 && field != 12 && field != 22 && field != 23) + v = htonl(*((uint32_t*) value)); + else v = *((uint32_t*) value); memcpy(da->field->value , &v, OXM_LENGTH(da->field->header)); break; } case 8:{ - uint64_t v = hton64(*((uint64_t*) value)); + uint64_t v = ntoh64(*((uint64_t*) value)); memcpy(da->field->value , &v, OXM_LENGTH(da->field->header)); break; } diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 99ab5e56..3bd39043 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -105,7 +105,6 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) uint16_t v = (*(uint16_t*)act->field->value); vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) | (v & VLAN_VID_MASK)); - } break; } @@ -370,6 +369,15 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) ntohl(v & PBB_ISID_MASK); break; } + case OXM_OF_TUNNEL_ID :{ + struct ofl_match_tlv *f; + HMAP_FOR_EACH_WITH_HASH(f, struct ofl_match_tlv, + hmap_node, hash_int(OXM_OF_TUNNEL_ID, 0), &(pkt)->handle_std->match.match_fields){ + uint64_t *tunnel_id = (uint64_t*) f->value; + *tunnel_id = *((uint64_t*) act->field->value); + } + break; + } default: VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to set unknow field."); break; From 5ddff8147a9303ab231ff33cc76547000cdd62d7 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Thu, 9 Oct 2014 23:38:49 -0300 Subject: [PATCH 082/191] Fix OXM_SCTP_DST print --- oflib/ofl-print.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oflib/ofl-print.c b/oflib/ofl-print.c index 532aab77..7fe06b51 100644 --- a/oflib/ofl-print.c +++ b/oflib/ofl-print.c @@ -245,7 +245,7 @@ ofl_oxm_type_print(FILE *stream, uint32_t type){ case OXM_OF_UDP_SRC: {fprintf(stream, "udp_src"); return; } case OXM_OF_UDP_DST: {fprintf(stream, "udp_dst"); return; } case OXM_OF_SCTP_SRC: {fprintf(stream, "sctp_src"); return; } - case OXM_OF_SCTP_DST: {fprintf(stream, "udp_dst"); return; } + case OXM_OF_SCTP_DST: {fprintf(stream, "sctp_dst"); return; } case OXM_OF_ICMPV4_CODE: {fprintf(stream, "icmpv4_code"); return; } case OXM_OF_ICMPV4_TYPE: {fprintf(stream, "icmpv4_type"); return; } case OXM_OF_ARP_OP: {fprintf(stream, "arp_op"); return; } From 79941f0873bcc56c6f8d698951f6a26edea8bde7 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Thu, 9 Oct 2014 23:47:02 -0300 Subject: [PATCH 083/191] Fix malloc being called twice on reply_port and reply_queue unpack messages --- oflib/ofl-messages-unpack.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 0b2a582b..9c77c96c 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -1098,7 +1098,6 @@ ofl_msg_unpack_multipart_reply_port(struct ofp_multipart_reply *os, size_t *len, // ofp_multipart_reply was already checked and subtracted in unpack_multipart_reply stat = (struct ofp_port_stats *)os->body; - dm = (struct ofl_msg_multipart_reply_port *) malloc(sizeof(struct ofl_msg_multipart_reply_port)); error = ofl_utils_count_ofp_port_stats(stat, *len, &dm->stats_num); if (error) { @@ -1132,7 +1131,6 @@ ofl_msg_unpack_multipart_reply_queue(struct ofp_multipart_reply *os, size_t *len // ofp_multipart_reply was already checked and subtracted in unpack_multipart_reply stat = (struct ofp_queue_stats *)os->body; - dm = (struct ofl_msg_multipart_reply_queue *) malloc(sizeof(struct ofl_msg_multipart_reply_queue)); error = ofl_utils_count_ofp_queue_stats(stat, *len, &dm->stats_num); if (error) { From 167fb862bc12f012507df0e2ae2d06c63c33ca58 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Fri, 10 Oct 2014 19:41:00 -0300 Subject: [PATCH 084/191] Change tunnel_id from network to host byte order. Without these changes, flows were being added incorrectly. --- oflib/oxm-match.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/oflib/oxm-match.c b/oflib/oxm-match.c index b1da8c3f..cdf2f6e1 100644 --- a/oflib/oxm-match.c +++ b/oflib/oxm-match.c @@ -95,7 +95,7 @@ oxm_init(void) int i; for (i = 0; i < NUM_OXM_FIELDS; i++) { - struct oxm_field *f = &all_fields[i]; + struct oxm_field *f = &all_fields[i]; hmap_insert(&all_oxm_fields, &f->hmap_node, hash_int(f->header, 0)); } @@ -175,6 +175,7 @@ oxm_field_lookup(uint32_t header) struct oxm_field *f; oxm_init(); + HMAP_FOR_EACH_WITH_HASH(f, struct oxm_field, hmap_node, hash_int(header, 0), &all_oxm_fields) { if (f->header == header) { @@ -306,7 +307,6 @@ static uint8_t* get_oxm_value(struct ofl_match *m, uint32_t header){ static int parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, const void *value, const void *mask){ - switch (f->index) { case OFI_OXM_OF_IN_PORT: { uint32_t* in_port = (uint32_t*) value; @@ -510,9 +510,10 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, ofl_structs_match_put8(match, f->header, *v); return 0; } - case OFI_OXM_OF_PBB_ISID: + case OFI_OXM_OF_PBB_ISID:{ ofl_structs_match_put32(match, f->header, ntohl(*((uint32_t*) value))); return 0; + } case OFI_OXM_OF_PBB_ISID_W:{ if (check_bad_wildcard32(*((uint32_t*) value), *((uint32_t*) mask))){ return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); @@ -521,14 +522,14 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, return 0; } case OFI_OXM_OF_TUNNEL_ID:{ - ofl_structs_match_put64(match, f->header, *((uint64_t*) value)); + ofl_structs_match_put64(match, f->header, ntoh64(*((uint64_t*) value))); return 0; } case OFI_OXM_OF_TUNNEL_ID_W:{ if (check_bad_wildcard64(*((uint64_t*) value), *((uint64_t*) mask))){ return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); } - ofl_structs_match_put64m(match, f->header,*((uint64_t*) value),*((uint64_t*) mask)); + ofl_structs_match_put64m(match, f->header,ntoh64(*((uint64_t*) value)),ntoh64(*((uint64_t*) mask))); return 0; } case OFI_OXM_OF_IPV6_EXTHDR: From 440ef4f214d5ee322f119cf606ce00850e69c998 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Sat, 11 Oct 2014 01:30:35 -0300 Subject: [PATCH 085/191] Fix search packe_handle validate search for tunnel_id. The previous code was searching for OXM_METADATA, leading to erroneous tunnel_id overwriting. --- udatapath/packet_handle_std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/udatapath/packet_handle_std.c b/udatapath/packet_handle_std.c index 62a322f3..21a7c3e2 100644 --- a/udatapath/packet_handle_std.c +++ b/udatapath/packet_handle_std.c @@ -61,7 +61,7 @@ packet_handle_std_validate(struct packet_handle_std *handle) { } HMAP_FOR_EACH_WITH_HASH(f, struct ofl_match_tlv, - hmap_node, hash_int(OXM_OF_METADATA,0), &handle->match.match_fields){ + hmap_node, hash_int(OXM_OF_TUNNEL_ID,0), &handle->match.match_fields){ tunnel_id = *((uint64_t*) f->value); } From 97c7b80e107b0e41ea45b20dc134bfcd35d84030 Mon Sep 17 00:00:00 2001 From: oftutorial Date: Sat, 11 Oct 2014 01:33:08 -0300 Subject: [PATCH 086/191] Change IPv6 flow label and traffic class parsing. This commit changes the parsing specification of the fields: version, traffic class and flow label. Now they are parsed as only one field on customnetpdl. --- customnetpdl.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/customnetpdl.xml b/customnetpdl.xml index 89796c45..1cb226e6 100644 --- a/customnetpdl.xml +++ b/customnetpdl.xml @@ -891,10 +891,10 @@ - - - - + + + + From 5e5774d6f1da27064edbfa7a0d5f936db0b86934 Mon Sep 17 00:00:00 2001 From: Aravindhan Dhanasekaran Date: Thu, 16 Oct 2014 00:41:50 -0400 Subject: [PATCH 087/191] 128: Hex metadata is being displayed in decimal in flow statistics --- oflib/ofl-structs-print.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index 830c6e23..62683ecc 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -398,9 +398,9 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0x1); break; case OFPXMT_OFB_METADATA: - fprintf(stream, "metadata=\"0x%"PRIu64"\"", *((uint64_t*) f->value)); + fprintf(stream, "metadata=\"0x%"PRIx64"\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", metadata_mask=\"0x%"PRIu64"\"", *((uint64_t*)(f->value+8))); + fprintf(stream, ", metadata_mask=\"0x%"PRIx64"\"", *((uint64_t*)(f->value+8))); } break; case OFPXMT_OFB_PBB_ISID : From 776cd0969cd068ccf1a87ae4a41fbd7ceede929e Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 20 Oct 2014 11:32:41 -0700 Subject: [PATCH 088/191] Fix memory problems in set table features, clean up loop indexes. --- oflib/ofl-structs.c | 4 ++++ udatapath/flow_table.c | 19 ++++++++++-------- udatapath/pipeline.c | 44 +++++++++++++++++++++++------------------- 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/oflib/ofl-structs.c b/oflib/ofl-structs.c index c3ea0716..cc6144c0 100644 --- a/oflib/ofl-structs.c +++ b/oflib/ofl-structs.c @@ -470,6 +470,10 @@ ofl_structs_free_group_desc_stats(struct ofl_group_desc_stats *stats, struct ofl void ofl_structs_free_table_features(struct ofl_table_features* features, struct ofl_exp *exp){ + /* We sometime sets it to NULL (see set feature request). Jean II */ + if (features == NULL) + return; + OFL_UTILS_FREE_ARR_FUN2(features->properties, features->properties_num, ofl_structs_free_table_properties, exp); free(features->name); diff --git a/udatapath/flow_table.c b/udatapath/flow_table.c index 0826fdf4..760a5ed9 100644 --- a/udatapath/flow_table.c +++ b/udatapath/flow_table.c @@ -278,12 +278,13 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp struct ofl_table_feature_prop_instructions *inst_capabilities; inst_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_instructions)); inst_capabilities->header.type = type; + inst_capabilities->instruction_ids = xmalloc(sizeof(instructions)); if (PIPELINE_TABLES > 1) { - inst_capabilities->ids_num = N_INSTRUCTIONS; - inst_capabilities->instruction_ids = instructions; + inst_capabilities->ids_num = N_INSTRUCTIONS; + memcpy(inst_capabilities->instruction_ids, instructions, sizeof(instructions)); } else { - inst_capabilities->ids_num = N_INSTRUCTIONS - 1; - inst_capabilities->instruction_ids = instructions_nogoto; + inst_capabilities->ids_num = N_INSTRUCTIONS - 1; + memcpy(inst_capabilities->instruction_ids, instructions_nogoto, sizeof(instructions_nogoto)); } inst_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&inst_capabilities->header, NULL); (*prop) = (struct ofl_table_feature_prop_header*) inst_capabilities; @@ -311,7 +312,8 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp act_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_actions)); act_capabilities->header.type = type; act_capabilities->actions_num= N_ACTIONS; - act_capabilities->action_ids = actions; + act_capabilities->action_ids = xmalloc(sizeof(actions)); + memcpy(act_capabilities->action_ids, actions, sizeof(actions)); act_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&act_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) act_capabilities; break; @@ -322,11 +324,11 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp case OFPTFPT_WRITE_SETFIELD: case OFPTFPT_WRITE_SETFIELD_MISS:{ struct ofl_table_feature_prop_oxm *oxm_capabilities; - int i; oxm_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); oxm_capabilities->header.type = type; oxm_capabilities->oxm_num = NUM_OXM_IDS; - oxm_capabilities->oxm_ids = oxm_ids; + oxm_capabilities->oxm_ids = xmalloc(sizeof(oxm_ids)); + memcpy(oxm_capabilities->oxm_ids, oxm_ids, sizeof(oxm_ids)); oxm_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&oxm_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) oxm_capabilities; break; @@ -336,7 +338,8 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp oxm_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_oxm)); oxm_capabilities->header.type = type; oxm_capabilities->oxm_num = NUM_WILD_IDS; - oxm_capabilities->oxm_ids = wildcarded; + oxm_capabilities->oxm_ids = xmalloc(sizeof(wildcarded)); + memcpy(oxm_capabilities->oxm_ids, wildcarded, sizeof(wildcarded)); oxm_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&oxm_capabilities->header, NULL); *prop = (struct ofl_table_feature_prop_header*) oxm_capabilities; break; diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index 6960bac1..71e2100b 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -373,10 +373,11 @@ ofl_err pipeline_handle_stats_request_table_features_request(struct pipeline *pl, struct ofl_msg_multipart_request_header *msg, const struct sender *sender) { - size_t i, j; struct ofl_table_features **features; struct ofl_msg_multipart_request_table_features *feat = (struct ofl_msg_multipart_request_table_features *) msg; + int i; /* Feature index in feature array. Jean II */ + int table_id; /* Further validation of request not done in * ofl_structs_table_features_unpack(). Jean II */ @@ -458,8 +459,8 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, /* Should check merge->tables_num instead. Jean II */ if(feat->table_features != NULL){ /* Disable all tables, they will be selectively re-enabled. */ - for(i = 0; i < PIPELINE_TABLES; i++){ - pl->tables[i]->disabled = true; + for(table_id = 0; table_id < PIPELINE_TABLES; table_id++){ + pl->tables[table_id]->disabled = true; } /* Change tables configuration TODO: Remove flows*/ @@ -468,52 +469,55 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, * expected, like OFPTFFC_BAD_TABLE... Jean II */ VLOG_DBG(LOG_MODULE, "pipeline_handle_stats_request_table_features_request: updating features"); for(i = 0; i < feat->tables_num; i++){ - /* Obvious memory leak. - * Obvious memory ownership issue when non-frag requests. - * Jean II */ - pl->tables[feat->table_features[i]->table_id]->features = feat->table_features[i]; - pl->tables[i]->disabled = false; + table_id = feat->table_features[i]->table_id; + + /* Replace whole table feature. */ + ofl_structs_free_table_features(pl->tables[table_id]->features, pl->dp->exp); + pl->tables[table_id]->features = feat->table_features[i]; + feat->table_features[i] = NULL; + + /* Re-enable table. */ + pl->tables[table_id]->disabled = false; } } /* Cleanup request. */ if(sender->remote->mp_req_msg != NULL) { - /* Can't free entire structure, we are pointing to it ! */ - //ofl_msg_free((struct ofl_msg_header *) sender->remote->mp_req_msg, NULL); - free(sender->remote->mp_req_msg); + ofl_msg_free((struct ofl_msg_header *) sender->remote->mp_req_msg, pl->dp->exp); sender->remote->mp_req_msg = NULL; sender->remote->mp_req_xid = 0; /* Currently not needed. Jean II. */ } - j = 0; + table_id = 0; /* Query for table capabilities */ loop: ; features = (struct ofl_table_features**) xmalloc(sizeof(struct ofl_table_features *) * 8); /* Return 8 tables per reply segment. */ for (i = 0; i < 8; i++){ /* Skip disabled tables. */ - while((j < PIPELINE_TABLES) && (pl->tables[j]->disabled == true)) - j++; + while((table_id < PIPELINE_TABLES) && (pl->tables[table_id]->disabled == true)) + table_id++; /* Stop at the last table. */ - if(j >= PIPELINE_TABLES) + if(table_id >= PIPELINE_TABLES) break; /* Use that table in the reply. */ - features[i] = pl->tables[j]->features; - j++; + features[i] = pl->tables[table_id]->features; + table_id++; } - VLOG_DBG(LOG_MODULE, "multipart reply: returning %zu tables, next table-id %zu", i, j); + VLOG_DBG(LOG_MODULE, "multipart reply: returning %d tables, next table-id %d", i, table_id); { struct ofl_msg_multipart_reply_table_features reply = {{{.type = OFPT_MULTIPART_REPLY}, .type = OFPMP_TABLE_FEATURES, - .flags = (j == PIPELINE_TABLES ? 0x00000000 : OFPMPF_REPLY_MORE) }, + .flags = (table_id == PIPELINE_TABLES ? 0x00000000 : OFPMPF_REPLY_MORE) }, .table_features = features, .tables_num = i }; dp_send_message(pl->dp, (struct ofl_msg_header *)&reply, sender); } - if (j < PIPELINE_TABLES){ + if (table_id < PIPELINE_TABLES){ goto loop; } + free(features); return 0; } From c532c3167523564d4ea9f9754628900a0e96000f Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 20 Oct 2014 11:45:59 -0700 Subject: [PATCH 089/191] Add simple validations to table feature request. --- udatapath/pipeline.c | 54 +++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index 71e2100b..e5a05fed 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -378,6 +378,7 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, (struct ofl_msg_multipart_request_table_features *) msg; int i; /* Feature index in feature array. Jean II */ int table_id; + ofl_err error = 0; /* Further validation of request not done in * ofl_structs_table_features_unpack(). Jean II */ @@ -458,26 +459,43 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, /*Check to see if the body is empty.*/ /* Should check merge->tables_num instead. Jean II */ if(feat->table_features != NULL){ - /* Disable all tables, they will be selectively re-enabled. */ - for(table_id = 0; table_id < PIPELINE_TABLES; table_id++){ - pl->tables[table_id]->disabled = true; - } - /* Change tables configuration - TODO: Remove flows*/ - /* TODO : In theory, tables should be in ascending order ! - * Maybe we could return an error if table number not - * expected, like OFPTFFC_BAD_TABLE... Jean II */ - VLOG_DBG(LOG_MODULE, "pipeline_handle_stats_request_table_features_request: updating features"); + int last_table_id = 0; + + /* Check that the table features make sense. */ for(i = 0; i < feat->tables_num; i++){ + /* Table-IDs must be in ascending order. */ table_id = feat->table_features[i]->table_id; + if(table_id < last_table_id) { + error = ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_TABLE); + break; + } + /* Can't go over out internal max-entries. */ + if (feat->table_features[i]->max_entries > FLOW_TABLE_MAX_ENTRIES) { + error = ofl_error(OFPET_TABLE_FEATURES_FAILED, OFPTFFC_BAD_ARGUMENT); + break; + } + } - /* Replace whole table feature. */ - ofl_structs_free_table_features(pl->tables[table_id]->features, pl->dp->exp); - pl->tables[table_id]->features = feat->table_features[i]; - feat->table_features[i] = NULL; + if (error == 0) { - /* Re-enable table. */ - pl->tables[table_id]->disabled = false; + /* Disable all tables, they will be selectively re-enabled. */ + for(table_id = 0; table_id < PIPELINE_TABLES; table_id++){ + pl->tables[table_id]->disabled = true; + } + /* Change tables configuration + TODO: Remove flows*/ + VLOG_DBG(LOG_MODULE, "pipeline_handle_stats_request_table_features_request: updating features"); + for(i = 0; i < feat->tables_num; i++){ + table_id = feat->table_features[i]->table_id; + + /* Replace whole table feature. */ + ofl_structs_free_table_features(pl->tables[table_id]->features, pl->dp->exp); + pl->tables[table_id]->features = feat->table_features[i]; + feat->table_features[i] = NULL; + + /* Re-enable table. */ + pl->tables[table_id]->disabled = false; + } } } @@ -488,6 +506,10 @@ pipeline_handle_stats_request_table_features_request(struct pipeline *pl, sender->remote->mp_req_xid = 0; /* Currently not needed. Jean II. */ } + if (error) { + return error; + } + table_id = 0; /* Query for table capabilities */ loop: ; From 062de452956b0d239a9257b6dd334bf682424cb7 Mon Sep 17 00:00:00 2001 From: Aravindhan Dhanasekaran Date: Thu, 13 Nov 2014 01:04:32 -0500 Subject: [PATCH 090/191] dpctl: Allow 'goto' instruction for a match-all rule --- utilities/dpctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 411c36e8..851d5711 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -1116,7 +1116,9 @@ parse_match(char *str, struct ofl_match_header **match) { ofl_structs_match_init(m); for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, "apply", strlen("apply")) == 0 || strncmp(token, "write", strlen("write")) == 0 ) { + if (strncmp(token, "apply", strlen("apply")) == 0 || + strncmp(token, "write", strlen("write")) == 0 || + strncmp(token, "goto", strlen("goto")) == 0) { break; } /* In_port */ From 09af316080932a40b649e1c9af4b5e3526bb2e54 Mon Sep 17 00:00:00 2001 From: Vitaliy Ivanov Date: Wed, 26 Nov 2014 16:35:32 +0200 Subject: [PATCH 091/191] More breaks for long strings for better readability. Following commit 3b28f740b8087896610072cfb36e20929f663cd9 do the same breakout of long strings for other tables. Increases readability. Signed-off-by: Vitaliy Ivanov --- oflib/ofl-messages-print.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/oflib/ofl-messages-print.c b/oflib/ofl-messages-print.c index 56dd96b5..c711f173 100644 --- a/oflib/ofl-messages-print.c +++ b/oflib/ofl-messages-print.c @@ -402,7 +402,7 @@ ofl_msg_print_stats_reply_table(struct ofl_msg_multipart_reply_table *msg, FILE for (i=0; istats_num; i++) { ofl_structs_table_stats_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -416,7 +416,7 @@ ofl_msg_print_stats_reply_port(struct ofl_msg_multipart_reply_port *msg, FILE *s for (i=0; istats_num; i++) { ofl_structs_port_stats_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -430,7 +430,7 @@ ofl_msg_print_stats_reply_queue(struct ofl_msg_multipart_reply_queue *msg, FILE for (i=0; istats_num; i++) { ofl_structs_queue_stats_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -444,7 +444,7 @@ ofl_msg_print_stats_reply_group(struct ofl_msg_multipart_reply_group *msg, FILE for (i=0; istats_num; i++) { ofl_structs_group_stats_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -458,7 +458,7 @@ ofl_msg_print_stats_reply_meter(struct ofl_msg_multipart_reply_meter *msg, FILE for (i=0; istats_num; i++) { ofl_structs_meter_stats_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -472,7 +472,7 @@ ofl_msg_print_stats_reply_meter_conf(struct ofl_msg_multipart_reply_meter_conf * for (i=0; istats_num; i++) { ofl_structs_meter_config_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -492,7 +492,7 @@ ofl_msg_print_stats_reply_group_desc(struct ofl_msg_multipart_reply_group_desc * for (i=0; istats_num; i++) { ofl_structs_group_desc_stats_print(stream, msg->stats[i], exp); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "]"); @@ -529,7 +529,7 @@ static void ofl_msg_print_stats_reply_group_features(struct ofl_msg_multipart_re } } if (i < 3) - fprintf(stream, ", "); + fprintf(stream, ",\n"); } } @@ -561,7 +561,7 @@ ofl_msg_print_port_desc_reply(struct ofl_msg_multipart_reply_port_desc *msg, FIL for(i = 0; i < msg->stats_num; i++){ ofl_structs_port_print(stream, msg->stats[i]); - if (i < msg->stats_num - 1) { fprintf(stream, ", "); }; + if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; } fprintf(stream, "}"); } From 79204a0d67731bece4c7f2980cf8398679681296 Mon Sep 17 00:00:00 2001 From: Vitaliy Ivanov Date: Wed, 26 Nov 2014 16:41:06 +0200 Subject: [PATCH 092/191] trivial: empty lines and tabs vs spaces correction. Signed-off-by: Vitaliy Ivanov --- oflib/ofl-messages-print.c | 39 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/oflib/ofl-messages-print.c b/oflib/ofl-messages-print.c index c711f173..09996dec 100644 --- a/oflib/ofl-messages-print.c +++ b/oflib/ofl-messages-print.c @@ -329,7 +329,7 @@ ofl_msg_print_multipart_request(struct ofl_msg_multipart_request_header *msg, FI break; } case OFPMP_TABLE_FEATURES: { - ofl_msg_print_table_features_request((struct ofl_msg_multipart_request_table_features*)msg, stream); + ofl_msg_print_table_features_request((struct ofl_msg_multipart_request_table_features*)msg, stream); break; } case OFPMP_PORT_STATS: { @@ -357,7 +357,7 @@ ofl_msg_print_multipart_request(struct ofl_msg_multipart_request_header *msg, FI } case OFPMP_METER_FEATURES:{ break; - } + } case OFPMP_PORT_DESC:{ break; } @@ -510,17 +510,17 @@ static void ofl_msg_print_stats_reply_group_features(struct ofl_msg_multipart_re fprintf(stream, ": max_groups=%d, actions= ", msg->max_groups[i]); if(msg->actions[i] & 1){ ofl_action_type_print(stream, OFPAT_OUTPUT); - fprintf(stream, "/"); + fprintf(stream, "/"); } if(msg->actions[i] & OFPAT_COPY_TTL_OUT){ ofl_action_type_print(stream, OFPAT_COPY_TTL_OUT); - fprintf(stream, "/"); + fprintf(stream, "/"); } - if(msg->actions[i] & OFPAT_COPY_TTL_IN){ + if(msg->actions[i] & OFPAT_COPY_TTL_IN){ ofl_action_type_print(stream, OFPAT_COPY_TTL_IN); - fprintf(stream, "/"); + fprintf(stream, "/"); } for(j = OFPAT_SET_MPLS_TTL; j < OFPAT_POP_PBB; j++){ if (msg->actions[i] & j){ @@ -558,7 +558,7 @@ ofl_msg_print_table_features_reply(struct ofl_msg_multipart_reply_table_features static void ofl_msg_print_port_desc_reply(struct ofl_msg_multipart_reply_port_desc *msg, FILE *stream) { size_t i; - + for(i = 0; i < msg->stats_num; i++){ ofl_structs_port_print(stream, msg->stats[i]); if (i < msg->stats_num - 1) { fprintf(stream, ",\n"); }; @@ -630,7 +630,7 @@ ofl_msg_print_multipart_reply(struct ofl_msg_multipart_reply_header *msg, FILE * } case OFPMP_METER_CONFIG:{ ofl_msg_print_stats_reply_meter_conf((struct ofl_msg_multipart_reply_meter_conf*)msg, stream); - break; + break; } case OFPMP_METER_FEATURES:{ ofl_msg_print_reply_meter_features((struct ofl_msg_multipart_reply_meter_features*)msg, stream); @@ -672,16 +672,16 @@ ofl_msg_print_queue_get_config_reply(struct ofl_msg_queue_get_config_reply *msg, fprintf(stream, "]}"); } -static void +static void ofl_msg_print_role_msg(struct ofl_msg_role_request *msg, FILE *stream){ - + fprintf(stream, "{role= %d, generation_id= %"PRIu64"}", msg->role, msg->generation_id); } static void ofl_msg_print_async(struct ofl_msg_async_config* msg, FILE *stream){ - + fprintf(stream, "{"); ofl_structs_async_config_print(stream, msg->config); fprintf(stream, "}"); @@ -749,19 +749,18 @@ ofl_msg_print(FILE *stream, struct ofl_msg_header *msg, struct ofl_exp *exp) { /*Role messages */ case OFPT_ROLE_REQUEST: case OFPT_ROLE_REPLY:{ - ofl_msg_print_role_msg((struct ofl_msg_role_request*)msg, stream); + ofl_msg_print_role_msg((struct ofl_msg_role_request*)msg, stream); } /* Queue Configuration messages. */ case OFPT_QUEUE_GET_CONFIG_REQUEST: { ofl_msg_print_queue_get_config_request((struct ofl_msg_queue_get_config_request *)msg, stream); return; } case OFPT_QUEUE_GET_CONFIG_REPLY: { ofl_msg_print_queue_get_config_reply((struct ofl_msg_queue_get_config_reply *)msg, stream); return; } - - /* Asynchronous message configuration. */ - case OFPT_GET_ASYNC_REQUEST:{return;} + + /* Asynchronous message configuration. */ + case OFPT_GET_ASYNC_REQUEST:{return;} case OFPT_GET_ASYNC_REPLY: - case OFPT_SET_ASYNC:{ofl_msg_print_async((struct ofl_msg_async_config*)msg, stream); return;} - - case OFPT_METER_MOD: {ofl_msg_print_meter_mod((struct ofl_msg_meter_mod*)msg, stream); return;} - - } + case OFPT_SET_ASYNC:{ofl_msg_print_async((struct ofl_msg_async_config*)msg, stream); return;} + + case OFPT_METER_MOD: {ofl_msg_print_meter_mod((struct ofl_msg_meter_mod*)msg, stream); return;} + } } From fd4c11ba7603f64daee15349de63e03b61c15e94 Mon Sep 17 00:00:00 2001 From: Vitaliy Ivanov Date: Wed, 26 Nov 2014 16:42:28 +0200 Subject: [PATCH 093/191] treewide: remove *.bak files. Signed-off-by: Vitaliy Ivanov --- lib/dpif.c.bak | 392 -------- lib/ofpstat.c.bak | 259 ------ lib/ofpstat.h.bak | 102 --- lib/rconn.c.bak | 985 -------------------- lib/vconn.h.bak | 82 -- utilities/dpctl.c.bak | 1980 ----------------------------------------- 6 files changed, 3800 deletions(-) delete mode 100644 lib/dpif.c.bak delete mode 100644 lib/ofpstat.c.bak delete mode 100644 lib/ofpstat.h.bak delete mode 100644 lib/rconn.c.bak delete mode 100644 lib/vconn.h.bak delete mode 100644 utilities/dpctl.c.bak diff --git a/lib/dpif.c.bak b/lib/dpif.c.bak deleted file mode 100644 index 9a6a7232..00000000 --- a/lib/dpif.c.bak +++ /dev/null @@ -1,392 +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 "dpif.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "netlink.h" -#include "netlink-protocol.h" -#include "ofpbuf.h" -#include "openflow/openflow-netlink.h" -#include "openflow/openflow.h" -#include "packets.h" -#include "util.h" -#include "xtoxll.h" - -#include "vlog.h" -#define LOG_MODULE VLM_dpif - -/* Not really much point in logging many dpif errors. */ -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 60); - -/* The Generic Netlink family number used for OpenFlow. */ -static int openflow_family; - -static int lookup_openflow_multicast_group(int dp_idx, int *multicast_group); -static int send_mgmt_command(struct dpif *, int dp_idx, int command, - const char *netdev); - -/* Opens a socket for a local datapath, initializing 'dp'. If - * 'subscribe_dp_idx' is nonnegative, listens for asynchronous messages - * (packet-in, etc.) from the datapath with that number; otherwise, 'dp' will - * receive only replies to explicitly initiated requests. */ -int -dpif_open(int subscribe_dp_idx, struct dpif *dp) -{ - struct nl_sock *sock; - int multicast_group = 0; - int retval; - - retval = nl_lookup_genl_family(DP_GENL_FAMILY_NAME, &openflow_family); - if (retval) { - return retval; - } - - if (subscribe_dp_idx >= 0) { - retval = lookup_openflow_multicast_group(subscribe_dp_idx, - &multicast_group); - if (retval) { - return retval; - } - } - - /* Specify a large so_rcvbuf size because we occasionally need to be able - * to retrieve large collections of flow records. */ - retval = nl_sock_create(NETLINK_GENERIC, multicast_group, 0, - 4 * 1024u * 1024, &sock); - if (retval) { - return retval; - } - - dp->sock = sock; - return 0; -} - -/* Closes 'dp'. */ -void -dpif_close(struct dpif *dp) -{ - if (dp) { - nl_sock_destroy(dp->sock); - } -} - -static const struct nl_policy openflow_policy[] = { - [DP_GENL_A_DP_IDX] = { .type = NL_A_U32, - .optional = false }, - [DP_GENL_A_OPENFLOW] = { .type = NL_A_UNSPEC, - .min_len = sizeof(struct ofp_header), - .max_len = 65535, - .optional = false }, -}; - -/* Tries to receive an openflow message from datapath 'dp_idx' on 'sock'. If - * successful, stores the received message into '*msgp' and returns 0. The - * caller is responsible for destroying the message with ofpbuf_delete(). On - * failure, returns a positive errno value and stores a null pointer into - * '*msgp'. - * - * Only Netlink messages with embedded OpenFlow messages are accepted. Other - * Netlink messages provoke errors. - * - * If 'wait' is true, dpif_recv_openflow waits for a message to be ready; - * otherwise, returns EAGAIN if the 'sock' receive buffer is empty. */ -int -dpif_recv_openflow(struct dpif *dp, int dp_idx, struct ofpbuf **bufferp, - bool wait) -{ - struct nlattr *attrs[ARRAY_SIZE(openflow_policy)]; - struct ofpbuf *buffer; - struct ofp_header *oh; - uint16_t ofp_len; - - buffer = *bufferp = NULL; - do { - int retval; - - do { - ofpbuf_delete(buffer); - retval = nl_sock_recv(dp->sock, &buffer, wait); - } while (retval == ENOBUFS - || (!retval - && (nl_msg_nlmsghdr(buffer)->nlmsg_type == NLMSG_DONE - || nl_msg_nlmsgerr(buffer, NULL)))); - if (retval) { - if (retval != EAGAIN) { - VLOG_WARN_RL(LOG_MODULE, &rl, "dpif_recv_openflow: %s", strerror(retval)); - } - return retval; - } - - if (nl_msg_genlmsghdr(buffer) == NULL) { - VLOG_DBG_RL(LOG_MODULE, &rl, "received packet too short for Generic Netlink"); - goto error; - } - if (nl_msg_nlmsghdr(buffer)->nlmsg_type != openflow_family) { - VLOG_DBG_RL(LOG_MODULE, &rl, - "received type (%"PRIu16") != openflow family (%d)", - nl_msg_nlmsghdr(buffer)->nlmsg_type, openflow_family); - goto error; - } - - if (!nl_policy_parse(buffer, NLMSG_HDRLEN + GENL_HDRLEN, - openflow_policy, attrs, - ARRAY_SIZE(openflow_policy))) { - goto error; - } - } while (nl_attr_get_u32(attrs[DP_GENL_A_DP_IDX]) != dp_idx); - - oh = buffer->data = (void *) nl_attr_get(attrs[DP_GENL_A_OPENFLOW]); - buffer->size = nl_attr_get_size(attrs[DP_GENL_A_OPENFLOW]); - ofp_len = ntohs(oh->length); - if (ofp_len != buffer->size) { - VLOG_WARN_RL(LOG_MODULE, &rl, - "ofp_header.length %"PRIu16" != attribute length %zu\n", - ofp_len, buffer->size); - buffer->size = MIN(ofp_len, buffer->size); - } - *bufferp = buffer; - return 0; - -error: - ofpbuf_delete(buffer); - return EPROTO; -} - -/* Encapsulates 'msg', which must contain an OpenFlow message, in a Netlink - * message, and sends it to the OpenFlow local datapath numbered 'dp_idx' via - * 'sock'. - * - * Returns 0 if successful, otherwise a positive errno value. Returns EAGAIN - * if the 'sock' send buffer is full. - * - * If the send is successful, then the kernel module will receive it, but there - * is no guarantee that any reply will not be dropped (see nl_sock_transact() - * for details). - */ -int -dpif_send_openflow(struct dpif *dp, int dp_idx, struct ofpbuf *buffer) -{ - struct ofp_header *oh; - unsigned int dump_flag; - struct ofpbuf hdr; - struct nlattr *nla; - uint32_t fixed_buffer[64 / 4]; - struct iovec iov[3]; - int pad_bytes; - int n_iov; - int retval; - - /* The reply to OFPT_STATS_REQUEST may be multiple segments long, so we - * need to specify NLM_F_DUMP in the request. */ - oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); - dump_flag = oh->type == OFPT_STATS_REQUEST ? NLM_F_DUMP : 0; - - ofpbuf_use(&hdr, fixed_buffer, sizeof fixed_buffer); - nl_msg_put_genlmsghdr(&hdr, dp->sock, 32, openflow_family, - NLM_F_REQUEST | dump_flag, DP_GENL_C_OPENFLOW, 1); - nl_msg_put_u32(&hdr, DP_GENL_A_DP_IDX, dp_idx); - nla = ofpbuf_put_uninit(&hdr, sizeof *nla); - nla->nla_len = sizeof *nla + buffer->size; - nla->nla_type = DP_GENL_A_OPENFLOW; - pad_bytes = NLA_ALIGN(nla->nla_len) - nla->nla_len; - nl_msg_nlmsghdr(&hdr)->nlmsg_len = hdr.size + buffer->size + pad_bytes; - n_iov = 2; - iov[0].iov_base = hdr.data; - iov[0].iov_len = hdr.size; - iov[1].iov_base = buffer->data; - iov[1].iov_len = buffer->size; - if (pad_bytes) { - static char zeros[NLA_ALIGNTO]; - n_iov++; - iov[2].iov_base = zeros; - iov[2].iov_len = pad_bytes; - } - retval = nl_sock_sendv(dp->sock, iov, n_iov, false); - if (retval && retval != EAGAIN) { - VLOG_WARN_RL(LOG_MODULE, &rl, "dpif_send_openflow: %s", strerror(retval)); - } - return retval; -} - -/* Creates local datapath numbered 'dp_idx' with the name 'dp_name'. A - * 'dp_idx' of -1 or null 'dp_name' will have the kernel module choose values. - * (At least one or the other must be provided, however, so that the caller can - * identify the datapath that was created.) Returns 0 if successful, otherwise - * a positive errno value. */ -int -dpif_add_dp(struct dpif *dp, int dp_idx, const char *dp_name) -{ - return send_mgmt_command(dp, dp_idx, DP_GENL_C_ADD_DP, dp_name); -} - -/* Destroys a local datapath. If 'dp_idx' is not -1, destroys the datapath - * with that number; if 'dp_name' is not NULL, destroys the datapath with that - * name. Exactly one of 'dp_idx' and 'dp_name' should be used. Returns 0 if - * successful, otherwise a positive errno value. */ -int -dpif_del_dp(struct dpif *dp, int dp_idx, const char *dp_name) -{ - return send_mgmt_command(dp, dp_idx, DP_GENL_C_DEL_DP, dp_name); -} - -/* Adds the Ethernet device named 'netdev' to the local datapath numbered - * 'dp_idx'. Returns 0 if successful, otherwise a positive errno value. */ -int -dpif_add_port(struct dpif *dp, int dp_idx, const char *netdev) -{ - return send_mgmt_command(dp, dp_idx, DP_GENL_C_ADD_PORT, netdev); -} - -/* Removes the Ethernet device named 'netdev' from the local datapath numbered - * 'dp_idx'. Returns 0 if successful, otherwise a positive errno value. */ -int -dpif_del_port(struct dpif *dp, int dp_idx, const char *netdev) -{ - return send_mgmt_command(dp, dp_idx, DP_GENL_C_DEL_PORT, netdev); -} - -static const struct nl_policy openflow_multicast_policy[] = { - [DP_GENL_A_DP_IDX] = { .type = NL_A_U32 }, - [DP_GENL_A_DP_NAME] = { .type = NL_A_STRING }, - [DP_GENL_A_MC_GROUP] = { .type = NL_A_U32 }, -}; - -/* Looks up the Netlink multicast group and datapath index of a datapath - * by either the datapath index or name. If 'dp_idx' points to a value - * of '-1', then 'dp_name' is used to lookup the datapath. If successful, - * stores the multicast group in '*multicast_group' and the index in - * '*dp_idx' and returns 0. Otherwise, returns a positive errno value. */ -static int -query_datapath(int *dp_idx, int *multicast_group, const char *dp_name) -{ - struct nl_sock *sock; - struct ofpbuf request, *reply; - struct nlattr *attrs[ARRAY_SIZE(openflow_multicast_policy)]; - int retval; - - retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &sock); - if (retval) { - return retval; - } - ofpbuf_init(&request, 0); - nl_msg_put_genlmsghdr(&request, sock, 0, openflow_family, NLM_F_REQUEST, - DP_GENL_C_QUERY_DP, 1); - if (*dp_idx != -1) { - nl_msg_put_u32(&request, DP_GENL_A_DP_IDX, *dp_idx); - } - if (dp_name) { - nl_msg_put_string(&request, DP_GENL_A_DP_NAME, dp_name); - } - retval = nl_sock_transact(sock, &request, &reply); - ofpbuf_uninit(&request); - if (retval) { - nl_sock_destroy(sock); - return retval; - } - if (!nl_policy_parse(reply, NLMSG_HDRLEN + GENL_HDRLEN, - openflow_multicast_policy, attrs, - ARRAY_SIZE(openflow_multicast_policy))) { - nl_sock_destroy(sock); - ofpbuf_delete(reply); - return EPROTO; - } - *dp_idx = nl_attr_get_u32(attrs[DP_GENL_A_DP_IDX]); - *multicast_group = nl_attr_get_u32(attrs[DP_GENL_A_MC_GROUP]); - nl_sock_destroy(sock); - ofpbuf_delete(reply); - - return 0; -} - -/* Looks up the Netlink multicast group used by datapath 'dp_idx'. If - * successful, stores the multicast group in '*multicast_group' and returns 0. - * Otherwise, returns a positve errno value. */ -static int -lookup_openflow_multicast_group(int dp_idx, int *multicast_group) -{ - return query_datapath(&dp_idx, multicast_group, NULL); -} - -/* Looks up the datatpath index based on the name. Returns the index, or - * -1 on error. */ -int -dpif_get_idx(const char *name) -{ - int dp_idx = -1; - int mc_group = 0; - - if (query_datapath(&dp_idx, &mc_group, name)) { - return -1; - } - - return dp_idx; -} - -/* Sends the given 'command' to datapath 'dp', related to the local datapath - * numbered 'dp_idx'. If 'arg' is nonnull, adds it to the command as the - * datapath or port name attribute depending on the requested operation. - * Returns 0 if successful, otherwise a positive errno value. */ -static int -send_mgmt_command(struct dpif *dp, int dp_idx, int command, const char *arg) -{ - struct ofpbuf request, *reply; - int retval; - - ofpbuf_init(&request, 0); - nl_msg_put_genlmsghdr(&request, dp->sock, 32, openflow_family, - NLM_F_REQUEST | NLM_F_ACK, command, 1); - if (dp_idx != -1) { - nl_msg_put_u32(&request, DP_GENL_A_DP_IDX, dp_idx); - } - if (arg) { - if ((command == DP_GENL_C_ADD_DP) || (command == DP_GENL_C_DEL_DP)) { - nl_msg_put_string(&request, DP_GENL_A_DP_NAME, arg); - } else { - nl_msg_put_string(&request, DP_GENL_A_PORTNAME, arg); - } - } - retval = nl_sock_transact(dp->sock, &request, &reply); - ofpbuf_uninit(&request); - ofpbuf_delete(reply); - - return retval; -} diff --git a/lib/ofpstat.c.bak b/lib/ofpstat.c.bak deleted file mode 100644 index d14d70f2..00000000 --- a/lib/ofpstat.c.bak +++ /dev/null @@ -1,259 +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/openflow.h" -#include "ofpstat.h" - -#define INC_IFP_STAT(ifps, tag) do {++(ifps)->tag;} while (0) - -static void inc_protocol_message(struct ofpstat *, struct ofp_header *); -static void inc_error_notification(struct ofpstat *, struct ofp_header *); -static void inc_flow_manipulation(struct ofpstat *, struct ofp_header *); - -static void -inc_protocol_message(struct ofpstat *ifps, struct ofp_header *hdr) -{ - switch (hdr->type) { - case OFPT_HELLO: - INC_IFP_STAT(ifps, ofps_hello); - break; - case OFPT_ERROR: - INC_IFP_STAT(ifps, ofps_error); - break; - case OFPT_ECHO_REQUEST: - INC_IFP_STAT(ifps, ofps_echo_request); - break; - case OFPT_ECHO_REPLY: - INC_IFP_STAT(ifps, ofps_echo_reply); - break; - case OFPT_VENDOR: - INC_IFP_STAT(ifps, ofps_vendor); - break; - case OFPT_FEATURES_REQUEST: - INC_IFP_STAT(ifps, ofps_feats_request); - break; - case OFPT_FEATURES_REPLY: - INC_IFP_STAT(ifps, ofps_feats_reply); - break; - case OFPT_GET_CONFIG_REQUEST: - INC_IFP_STAT(ifps, ofps_get_config_request); - break; - case OFPT_GET_CONFIG_REPLY: - INC_IFP_STAT(ifps, ofps_get_config_reply); - break; - case OFPT_SET_CONFIG: - INC_IFP_STAT(ifps, ofps_set_config); - break; - case OFPT_PACKET_IN: - INC_IFP_STAT(ifps, ofps_packet_in); - break; - case OFPT_FLOW_REMOVED: - INC_IFP_STAT(ifps, ofps_flow_removed); - break; - case OFPT_PORT_STATUS: - INC_IFP_STAT(ifps, ofps_port_status); - break; - case OFPT_PACKET_OUT: - INC_IFP_STAT(ifps, ofps_packet_out); - break; - case OFPT_FLOW_MOD: - INC_IFP_STAT(ifps, ofps_flow_mod); - break; - case OFPT_PORT_MOD: - INC_IFP_STAT(ifps, ofps_port_mod); - break; - case OFPT_MULTIPART_REQUEST: - INC_IFP_STAT(ifps, ofps_stats_request); - break; - case OFPT_MULTIPART_REPLY: - INC_IFP_STAT(ifps, ofps_stats_reply); - break; - case OFPT_BARRIER_REQUEST: - INC_IFP_STAT(ifps, ofps_barrier_request); - break; - case OFPT_BARRIER_REPLY: - INC_IFP_STAT(ifps, ofps_barrier_reply); - break; - default: - INC_IFP_STAT(ifps, ofps_unknown); - break; - } -} - -static void -inc_error_notification(struct ofpstat *ifps, struct ofp_header *hdr) -{ - struct ofp_error_msg *errmsg = (struct ofp_error_msg *)hdr; - uint16_t errtype = ntohs(errmsg->type); - uint16_t errcode = ntohs(errmsg->code); - - switch (errtype) { - case OFPET_HELLO_FAILED: - INC_IFP_STAT(ifps, ofps_error_type.hello_fail); - switch (errcode) { - case OFPHFC_INCOMPATIBLE: - INC_IFP_STAT(ifps, ofps_error_code.hf_incompat); - break; - case OFPHFC_EPERM: - INC_IFP_STAT(ifps, ofps_error_code.hf_eperm); - break; - default: - INC_IFP_STAT(ifps, ofps_error_code.unknown); - break; - } - break; - case OFPET_BAD_REQUEST: - INC_IFP_STAT(ifps, ofps_error_type.bad_request); - switch (errcode) { - case OFPBRC_BAD_VERSION: - INC_IFP_STAT(ifps, ofps_error_code.br_bad_version); - break; - case OFPBRC_BAD_TYPE: - INC_IFP_STAT(ifps, ofps_error_code.br_bad_type); - break; - case OFPBRC_BAD_STAT: - INC_IFP_STAT(ifps, ofps_error_code.br_bad_stat); - break; - case OFPBRC_BAD_VENDOR: - INC_IFP_STAT(ifps, ofps_error_code.br_bad_vendor); - break; - case OFPBRC_EPERM: - INC_IFP_STAT(ifps, ofps_error_code.br_eperm); - break; - default: - INC_IFP_STAT(ifps, ofps_error_code.unknown); - break; - } - break; - case OFPET_BAD_ACTION: - INC_IFP_STAT(ifps, ofps_error_type.bad_action); - switch (errcode) { - case OFPBAC_BAD_TYPE: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_type); - break; - case OFPBAC_BAD_LEN: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_len); - break; - case OFPBAC_BAD_VENDOR: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_vendor); - break; - case OFPBAC_BAD_VENDOR_TYPE: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_vendor_type); - break; - case OFPBAC_BAD_OUT_PORT: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_out_port); - break; - case OFPBAC_BAD_ARGUMENT: - INC_IFP_STAT(ifps, ofps_error_code.ba_bad_argument); - break; - case OFPBAC_EPERM: - INC_IFP_STAT(ifps, ofps_error_code.ba_eperm); - break; - default: - INC_IFP_STAT(ifps, ofps_error_code.unknown); - break; - } - break; - case OFPET_FLOW_MOD_FAILED: - INC_IFP_STAT(ifps, ofps_error_type.flow_mod_fail); - switch (errcode) { - case OFPFMFC_ALL_TABLES_FULL: - INC_IFP_STAT(ifps, ofps_error_code.fmf_all_tables_full); - break; - case OFPFMFC_OVERLAP: - INC_IFP_STAT(ifps, ofps_error_code.fmf_overlap); - break; - case OFPFMFC_EPERM: - INC_IFP_STAT(ifps, ofps_error_code.fmf_eperm); - break; - case OFPFMFC_BAD_EMERG_TIMEOUT: - INC_IFP_STAT(ifps, ofps_error_code.fmf_emerg); - break; - default: - INC_IFP_STAT(ifps, ofps_error_code.unknown); - break; - } - break; - default: - INC_IFP_STAT(ifps, ofps_error_type.unknown); - break; - } -} - -static void -inc_flow_manipulation(struct ofpstat *ifps, struct ofp_header *hdr) -{ - struct ofp_flow_mod *flowmodmsg = (struct ofp_flow_mod *)hdr; - uint16_t flowmodops = ntohs(flowmodmsg->command); - - switch (flowmodops) { - case OFPFC_ADD: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.add); - break; - case OFPFC_MODIFY: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.modify); - break; - case OFPFC_MODIFY_STRICT: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.modify_strict); - break; - case OFPFC_DELETE: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.delete); - break; - case OFPFC_DELETE_STRICT: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.delete_strict); - break; - default: - INC_IFP_STAT(ifps, ofps_flow_mod_ops.unknown); - break; - } -} - -void -ofpstat_inc_protocol_stat(struct ofpstat *ifps, struct ofp_header *hdr) -{ - ++ifps->ofps_total; - inc_protocol_message(ifps, hdr); - - switch (hdr->type) { - case OFPT_ERROR: - inc_error_notification(ifps, hdr); - break; - case OFPT_FLOW_MOD: - inc_flow_manipulation(ifps, hdr); - break; - default: - break; - } -} diff --git a/lib/ofpstat.h.bak b/lib/ofpstat.h.bak deleted file mode 100644 index c7e21dde..00000000 --- a/lib/ofpstat.h.bak +++ /dev/null @@ -1,102 +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 OFPSTAT_H_ -#define OFPSTAT_H_ - -struct ofp_header; - -struct ofpstat { - uint64_t ofps_total; - uint64_t ofps_unknown; - - uint64_t ofps_hello; - uint64_t ofps_error; - struct { - uint64_t hello_fail; - uint64_t bad_request; - uint64_t bad_action; - uint64_t flow_mod_fail; - uint64_t unknown; - } ofps_error_type; - struct { - uint64_t hf_incompat; - uint64_t hf_eperm; - uint64_t br_bad_version; - uint64_t br_bad_type; - uint64_t br_bad_stat; - uint64_t br_bad_vendor; - uint64_t br_eperm; - uint64_t ba_bad_type; - uint64_t ba_bad_len; - uint64_t ba_bad_vendor; - uint64_t ba_bad_vendor_type; - uint64_t ba_bad_out_port; - uint64_t ba_bad_argument; - uint64_t ba_eperm; - uint64_t fmf_all_tables_full; - uint64_t fmf_overlap; - uint64_t fmf_eperm; - uint64_t fmf_emerg; - uint64_t unknown; - } ofps_error_code; - uint64_t ofps_echo_request; - uint64_t ofps_echo_reply; - uint64_t ofps_vendor; - uint64_t ofps_feats_request; - uint64_t ofps_feats_reply; - uint64_t ofps_get_config_request; - uint64_t ofps_get_config_reply; - uint64_t ofps_set_config; - uint64_t ofps_packet_in; - uint64_t ofps_flow_removed; - uint64_t ofps_port_status; - uint64_t ofps_packet_out; - uint64_t ofps_flow_mod; - struct { - uint64_t add; - uint64_t modify; - uint64_t modify_strict; - uint64_t delete; - uint64_t delete_strict; - uint64_t unknown; - } ofps_flow_mod_ops; - uint64_t ofps_port_mod; - uint64_t ofps_stats_request; - uint64_t ofps_stats_reply; - uint64_t ofps_barrier_request; - uint64_t ofps_barrier_reply; -}; - -void ofpstat_inc_protocol_stat(struct ofpstat *, struct ofp_header *); - -#endif diff --git a/lib/rconn.c.bak b/lib/rconn.c.bak deleted file mode 100644 index a46b0b31..00000000 --- a/lib/rconn.c.bak +++ /dev/null @@ -1,985 +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 "rconn.h" -#include -#include -#include -#include -#include -#include "ofp.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "poll-loop.h" -#include "sat-math.h" -#include "timeval.h" -#include "util.h" -#include "vconn.h" -#include "vconn-provider.h" - -#define LOG_MODULE VLM_rconn -#include "vlog.h" - -#define STATES \ - STATE(VOID, 1 << 0) \ - STATE(BACKOFF, 1 << 1) \ - STATE(CONNECTING, 1 << 2) \ - STATE(ACTIVE, 1 << 3) \ - STATE(IDLE, 1 << 4) -enum state { -#define STATE(NAME, VALUE) S_##NAME = VALUE, - STATES -#undef STATE -}; - -static const char * -state_name(enum state state) -{ - switch (state) { -#define STATE(NAME, VALUE) case S_##NAME: return #NAME; - STATES -#undef STATE - } - return "***ERROR***"; -} - -/* A reliable connection to an OpenFlow switch or controller. - * - * See the large comment in rconn.h for more information. */ -struct rconn { - enum state state; - time_t state_entered; - - struct vconn *vconn; - char *name; - bool reliable; - - struct ofp_queue txq; - - int backoff; - int max_backoff; - time_t backoff_deadline; - time_t last_received; - time_t last_connected; - unsigned int packets_sent; - unsigned int seqno; - - /* In S_ACTIVE and S_IDLE, probably_admitted reports whether we believe - * that the peer has made a (positive) admission control decision on our - * connection. If we have not yet been (probably) admitted, then the - * connection does not reset the timer used for deciding whether the switch - * should go into fail-open mode. - * - * last_admitted reports the last time we believe such a positive admission - * control decision was made. */ - bool probably_admitted; - time_t last_admitted; - - /* These values are simply for statistics reporting, not used directly by - * anything internal to the rconn (or the secchan for that matter). */ - unsigned int packets_received; - unsigned int n_attempted_connections, n_successful_connections; - time_t creation_time; - unsigned long int total_time_connected; - - /* If we can't connect to the peer, it could be for any number of reasons. - * Usually, one would assume it is because the peer is not running or - * because the network is partitioned. But it could also be because the - * network topology has changed, in which case the upper layer will need to - * reassess it (in particular, obtain a new IP address via DHCP and find - * the new location of the controller). We set this flag when we suspect - * that this could be the case. */ - bool questionable_connectivity; - time_t last_questioned; - - /* Throughout this file, "probe" is shorthand for "inactivity probe". - * When nothing has been received from the peer for a while, we send out - * an echo request as an inactivity probe packet. We should receive back - * a response. */ - int probe_interval; /* Secs of inactivity before sending probe. */ - - /* Messages sent or received are copied to the monitor connections. */ -#define MAX_MONITORS 8 - struct vconn *monitors[8]; - size_t n_monitors; - - /* Protocol statistical informaition. */ - /* TODO Zoltan: Temporarily removed when moving to OpenFlow 1.1 */ - /* - struct ofpstat ofps_rcvd; - struct ofpstat ofps_sent; - */ - - uint32_t idle_echo_xid; -}; - -static unsigned int elapsed_in_this_state(const struct rconn *); -static unsigned int timeout(const struct rconn *); -static bool timed_out(const struct rconn *); -static void state_transition(struct rconn *, enum state); -static int try_send(struct rconn *); -static int reconnect(struct rconn *); -static void disconnect(struct rconn *, int error); -static void flush_queue(struct rconn *); -static void question_connectivity(struct rconn *); -static void copy_to_monitor(struct rconn *, const struct ofpbuf *); -static bool is_connected_state(enum state); -static bool is_admitted_msg(const struct ofpbuf *); - -/* Creates a new rconn, connects it (reliably) to 'name', and returns it. */ -struct rconn * -rconn_new(const char *name, int inactivity_probe_interval, int max_backoff) -{ - struct rconn *rc = rconn_create(inactivity_probe_interval, max_backoff); - rconn_connect(rc, name); - return rc; -} - -/* Creates a new rconn, connects it (unreliably) to 'vconn', and returns it. */ -struct rconn * -rconn_new_from_vconn(const char *name, struct vconn *vconn) -{ - struct rconn *rc = rconn_create(60, 0); - rconn_connect_unreliably(rc, name, vconn); - return rc; -} - -/* Creates and returns a new rconn. - * - * 'probe_interval' is a number of seconds. If the interval passes once - * without an OpenFlow message being received from the peer, the rconn sends - * out an "echo request" message. If the interval passes again without a - * message being received, the rconn disconnects and re-connects to the peer. - * Setting 'probe_interval' to 0 disables this behavior. - * - * 'max_backoff' is the maximum number of seconds between attempts to connect - * to the peer. The actual interval starts at 1 second and doubles on each - * failure until it reaches 'max_backoff'. If 0 is specified, the default of - * 60 seconds is used. */ -struct rconn * -rconn_create(int probe_interval, int max_backoff) -{ - struct rconn *rc = xcalloc(1, sizeof *rc); - - rc->state = S_VOID; - rc->state_entered = time_now(); - - rc->vconn = NULL; - rc->name = xstrdup("void"); - rc->reliable = false; - - queue_init(&rc->txq); - - rc->backoff = 0; - rc->max_backoff = max_backoff ? max_backoff : 60; - rc->backoff_deadline = TIME_MIN; - rc->last_received = time_now(); - rc->last_connected = time_now(); - rc->seqno = 0; - - rc->packets_sent = 0; - - rc->probably_admitted = false; - rc->last_admitted = time_now(); - - rc->packets_received = 0; - rc->n_attempted_connections = 0; - rc->n_successful_connections = 0; - rc->creation_time = time_now(); - rc->total_time_connected = 0; - - rc->questionable_connectivity = false; - rc->last_questioned = time_now(); - - rc->probe_interval = probe_interval ? MAX(1, probe_interval) : 0; - - rc->n_monitors = 0; - - /* TODO Zoltan: Temporarily removed when moving to OpenFlow 1.1 */ - /* - memset(&rc->ofps_rcvd, 0, sizeof(rc->ofps_rcvd)); - memset(&rc->ofps_sent, 0, sizeof(rc->ofps_sent)); - */ - - rc->idle_echo_xid = 0; - - return rc; -} - -int -rconn_connect(struct rconn *rc, const char *name) -{ - rconn_disconnect(rc); - free(rc->name); - rc->name = xstrdup(name); - rc->reliable = true; - return reconnect(rc); -} - -void -rconn_connect_unreliably(struct rconn *rc, - const char *name, struct vconn *vconn) -{ - assert(vconn != NULL); - rconn_disconnect(rc); - free(rc->name); - rc->name = xstrdup(name); - rc->reliable = false; - rc->vconn = vconn; - rc->last_connected = time_now(); - state_transition(rc, S_ACTIVE); -} - -void -rconn_disconnect(struct rconn *rc) -{ - if (rc->state != S_VOID) { - if (rc->vconn) { - vconn_close(rc->vconn); - rc->vconn = NULL; - } - free(rc->name); - rc->name = xstrdup("void"); - rc->reliable = false; - - rc->backoff = 0; - rc->backoff_deadline = TIME_MIN; - - state_transition(rc, S_VOID); - } -} - -/* Disconnects 'rc' and frees the underlying storage. */ -void -rconn_destroy(struct rconn *rc) -{ - if (rc) { - size_t i; - - free(rc->name); - vconn_close(rc->vconn); - flush_queue(rc); - queue_destroy(&rc->txq); - for (i = 0; i < rc->n_monitors; i++) { - vconn_close(rc->monitors[i]); - } - free(rc); - } -} - -static unsigned int -timeout_VOID(const struct rconn *rc UNUSED) -{ - return UINT_MAX; -} - -static void -run_VOID(struct rconn *rc UNUSED) -{ - /* Nothing to do. */ -} - -static int -reconnect(struct rconn *rc) -{ - int retval; - - VLOG_INFO(LOG_MODULE, "%s: connecting...", rc->name); - rc->n_attempted_connections++; - retval = vconn_open(rc->name, OFP_VERSION, &rc->vconn); - if (!retval) { - if (!vconn_is_reconnectable(rc->vconn)) { - rc->reliable = false; - } - rc->backoff_deadline = time_now() + rc->backoff; - state_transition(rc, S_CONNECTING); - } else { - VLOG_WARN(LOG_MODULE, "%s: connection failed (%s)", rc->name, strerror(retval)); - rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */ - disconnect(rc, 0); - } - return retval; -} - -static unsigned int -timeout_BACKOFF(const struct rconn *rc) -{ - return rc->backoff; -} - -static void -run_BACKOFF(struct rconn *rc) -{ - if (timed_out(rc)) { - reconnect(rc); - } -} - -static unsigned int -timeout_CONNECTING(const struct rconn *rc) -{ - return MAX(1, rc->backoff); -} - -static void -run_CONNECTING(struct rconn *rc) -{ - int retval = vconn_connect(rc->vconn); - if (!retval) { - VLOG_INFO(LOG_MODULE, "%s: connected", rc->name); - rc->n_successful_connections++; - state_transition(rc, S_ACTIVE); - rc->last_connected = rc->state_entered; - } else if (retval != EAGAIN) { - VLOG_INFO(LOG_MODULE, "%s: connection failed (%s)", rc->name, strerror(retval)); - disconnect(rc, retval); - } else if (timed_out(rc)) { - VLOG_INFO(LOG_MODULE, "%s: connection timed out", rc->name); - rc->backoff_deadline = TIME_MAX; /* Prevent resetting backoff. */ - disconnect(rc, 0); - } -} - -static void -do_tx_work(struct rconn *rc) -{ - if (!rc->txq.n) { - return; - } - while (rc->txq.n > 0) { - int error = try_send(rc); - if (error) { - break; - } - } - if (!rc->txq.n) { - poll_immediate_wake(); - } -} - -static unsigned int -timeout_ACTIVE(const struct rconn *rc) -{ - if (rc->probe_interval) { - unsigned int base = MAX(rc->last_received, rc->state_entered); - unsigned int arg = base + rc->probe_interval - rc->state_entered; - return arg; - } - return UINT_MAX; -} - -static void -run_ACTIVE(struct rconn *rc) -{ - if (timed_out(rc)) { - unsigned int base = MAX(rc->last_received, rc->state_entered); - VLOG_DBG(LOG_MODULE, "%s: idle %u seconds, sending inactivity probe", - rc->name, (unsigned int) (time_now() - base)); - - /* Ordering is important here: rconn_send() can transition to BACKOFF, - * and we don't want to transition back to IDLE if so, because then we - * can end up queuing a packet with vconn == NULL and then *boom*. */ - state_transition(rc, S_IDLE); - rconn_send(rc, make_echo_request(), NULL); - return; - } - - do_tx_work(rc); -} - -static unsigned int -timeout_IDLE(const struct rconn *rc) -{ - return rc->probe_interval; -} - -static void -run_IDLE(struct rconn *rc) -{ - if (timed_out(rc)) { - question_connectivity(rc); - VLOG_ERR(LOG_MODULE, "%s: no response to inactivity probe after %u " - "seconds, disconnecting", - rc->name, elapsed_in_this_state(rc)); - disconnect(rc, 0); - } else { - do_tx_work(rc); - } -} - -/* Performs whatever activities are necessary to maintain 'rc': if 'rc' is - * disconnected, attempts to (re)connect, backing off as necessary; if 'rc' is - * connected, attempts to send packets in the send queue, if any. */ -void -rconn_run(struct rconn *rc) -{ - int old_state; - do { - old_state = rc->state; - switch (rc->state) { -#define STATE(NAME, VALUE) case S_##NAME: run_##NAME(rc); break; - STATES -#undef STATE - default: - NOT_REACHED(); - } - } while (rc->state != old_state); -} - -/* Causes the next call to poll_block() to wake up when rconn_run() should be - * called on 'rc'. */ -void -rconn_run_wait(struct rconn *rc) -{ - unsigned int timeo = timeout(rc); - if (timeo != UINT_MAX) { - unsigned int expires = sat_add(rc->state_entered, timeo); - unsigned int remaining = sat_sub(expires, time_now()); - poll_timer_wait(sat_mul(remaining, 1000)); - } - - if ((rc->state & (S_ACTIVE | S_IDLE)) && rc->txq.n) { - vconn_wait(rc->vconn, WAIT_SEND); - } -} - -/* Attempts to receive a packet from 'rc'. If successful, returns the packet; - * otherwise, returns a null pointer. The caller is responsible for freeing - * the packet (with ofpbuf_delete()). */ -struct ofpbuf * -rconn_recv(struct rconn *rc) -{ - if (rc->state & (S_ACTIVE | S_IDLE)) { - struct ofpbuf *buffer; - int error = vconn_recv(rc->vconn, &buffer); - if (!error) { - struct ofp_header *h = buffer->data; - copy_to_monitor(rc, buffer); - if (is_admitted_msg(buffer) - || time_now() - rc->last_connected >= 30) { - rc->probably_admitted = true; - rc->last_admitted = time_now(); - } - rc->last_received = time_now(); - rc->packets_received++; - /* TODO Zoltan: Temporarily removed when moving to OpenFlow 1.1 */ - /* ofpstat_inc_protocol_stat(&rc->ofps_rcvd, h); */ - if (rc->state == S_IDLE) { - /* Check liveliness of a peer. */ - if (h->type == OFPT_ECHO_REPLY) { - if (rc->idle_echo_xid == 0) { - state_transition(rc, S_ACTIVE); - } else { - if (rc->idle_echo_xid == h->xid) - state_transition(rc, S_ACTIVE); - rc->idle_echo_xid = 0; - } - } else { - state_transition(rc, S_ACTIVE); - } - } - return buffer; - } else if (error != EAGAIN) { - disconnect(rc, error); - } - } - return NULL; -} - -/* Causes the next call to poll_block() to wake up when a packet may be ready - * to be received by vconn_recv() on 'rc'. */ -void -rconn_recv_wait(struct rconn *rc) -{ - if (rc->vconn) { - vconn_wait(rc->vconn, WAIT_RECV); - } -} - -/* Sends 'b' on 'rc'. Returns 0 if successful (in which case 'b' is - * destroyed), or ENOTCONN if 'rc' is not currently connected (in which case - * the caller retains ownership of 'b'). - * - * If 'n_queued' is non-null, then '*n_queued' will be incremented while the - * packet is in flight, then decremented when it has been sent (or discarded - * due to disconnection). Because 'b' may be sent (or discarded) before this - * function returns, the caller may not be able to observe any change in - * '*n_queued'. - * - * There is no rconn_send_wait() function: an rconn has a send queue that it - * takes care of sending if you call rconn_run(), which will have the side - * effect of waking up poll_block(). */ -int -rconn_send(struct rconn *rc, struct ofpbuf *b, int *n_queued) -{ - if (rconn_is_connected(rc)) { - copy_to_monitor(rc, b); - b->private_p = n_queued; - if (n_queued) { - ++*n_queued; - } - queue_push_tail(&rc->txq, b); - - /* If the queue was empty before we added 'b', try to send some - * packets. (But if the queue had packets in it, it's because the - * vconn is backlogged and there's no point in stuffing more into it - * now. We'll get back to that in rconn_run().) */ - if (rc->txq.n == 1) { - try_send(rc); - } - return 0; - } else { - return ENOTCONN; - } -} - -/* Sends 'b' on 'rc'. Increments '*n_queued' while the packet is in flight; it - * will be decremented when it has been sent (or discarded due to - * disconnection). Returns 0 if successful, EAGAIN if '*n_queued' is already - * at least as large as 'queue_limit', or ENOTCONN if 'rc' is not currently - * connected. Regardless of return value, 'b' is destroyed. - * - * Because 'b' may be sent (or discarded) before this function returns, the - * caller may not be able to observe any change in '*n_queued'. - * - * There is no rconn_send_wait() function: an rconn has a send queue that it - * takes care of sending if you call rconn_run(), which will have the side - * effect of waking up poll_block(). */ -int -rconn_send_with_limit(struct rconn *rc, struct ofpbuf *b, - int *n_queued, int queue_limit) -{ - int retval; - retval = *n_queued >= queue_limit ? EAGAIN : rconn_send(rc, b, n_queued); - if (retval) { - ofpbuf_delete(b); - } - return retval; -} - -/* Returns the total number of packets successfully sent on the underlying - * vconn. A packet is not counted as sent while it is still queued in the - * rconn, only when it has been successfuly passed to the vconn. */ -unsigned int -rconn_packets_sent(const struct rconn *rc) -{ - return rc->packets_sent; -} - -/* Adds 'vconn' to 'rc' as a monitoring connection, to which all messages sent - * and received on 'rconn' will be copied. 'rc' takes ownership of 'vconn'. */ -void -rconn_add_monitor(struct rconn *rc, struct vconn *vconn) -{ - if (rc->n_monitors < ARRAY_SIZE(rc->monitors)) { - VLOG_INFO(LOG_MODULE, "new monitor connection from %s", vconn_get_name(vconn)); - rc->monitors[rc->n_monitors++] = vconn; - } else { - VLOG_DBG(LOG_MODULE, "too many monitor connections, discarding %s", - vconn_get_name(vconn)); - vconn_close(vconn); - } -} - -/* Returns 'rc''s name (the 'name' argument passed to rconn_new()). */ -const char * -rconn_get_name(const struct rconn *rc) -{ - return rc->name; -} - -/* Returns true if 'rconn' is connected or in the process of reconnecting, - * false if 'rconn' is disconnected and will not reconnect on its own. */ -bool -rconn_is_alive(const struct rconn *rconn) -{ - return rconn->state != S_VOID; -} - -/* Returns true if 'rconn' is connected, false otherwise. */ -bool -rconn_is_connected(const struct rconn *rconn) -{ - return is_connected_state(rconn->state); -} - -/* Returns 0 if 'rconn' is connected. Otherwise, if 'rconn' is in a "failure - * mode" (that is, it is not connected), returns the number of seconds that it - * has been in failure mode, ignoring any times that it connected but the - * controller's admission control policy caused it to be quickly - * disconnected. */ -int -rconn_failure_duration(const struct rconn *rconn) -{ - return rconn_is_connected(rconn) ? 0 : time_now() - rconn->last_admitted; -} - -/* Returns the IP address of the peer, or 0 if the peer is not connected over - * an IP-based protocol or if its IP address is not known. */ -uint32_t -rconn_get_ip(const struct rconn *rconn) -{ - return rconn->vconn ? vconn_get_ip(rconn->vconn) : 0; -} - -/* If 'rconn' can't connect to the peer, it could be for any number of reasons. - * Usually, one would assume it is because the peer is not running or because - * the network is partitioned. But it could also be because the network - * topology has changed, in which case the upper layer will need to reassess it - * (in particular, obtain a new IP address via DHCP and find the new location - * of the controller). When this appears that this might be the case, this - * function returns true. It also clears the questionability flag and prevents - * it from being set again for some time. */ -bool -rconn_is_connectivity_questionable(struct rconn *rconn) -{ - bool questionable = rconn->questionable_connectivity; - rconn->questionable_connectivity = false; - return questionable; -} - -/* Returns the total number of packets successfully received by the underlying - * vconn. */ -unsigned int -rconn_packets_received(const struct rconn *rc) -{ - return rc->packets_received; -} - -/* Returns a string representing the internal state of 'rc'. The caller must - * not modify or free the string. */ -const char * -rconn_get_state(const struct rconn *rc) -{ - return state_name(rc->state); -} - -/* Returns the number of connection attempts made by 'rc', including any - * ongoing attempt that has not yet succeeded or failed. */ -unsigned int -rconn_get_attempted_connections(const struct rconn *rc) -{ - return rc->n_attempted_connections; -} - -/* Returns the number of successful connection attempts made by 'rc'. */ -unsigned int -rconn_get_successful_connections(const struct rconn *rc) -{ - return rc->n_successful_connections; -} - -/* Returns the time at which the last successful connection was made by - * 'rc'. */ -time_t -rconn_get_last_connection(const struct rconn *rc) -{ - return rc->last_connected; -} - -/* Returns the time at which 'rc' was created. */ -time_t -rconn_get_creation_time(const struct rconn *rc) -{ - return rc->creation_time; -} - -/* Returns the approximate number of seconds that 'rc' has been connected. */ -unsigned long int -rconn_get_total_time_connected(const struct rconn *rc) -{ - return (rc->total_time_connected - + (rconn_is_connected(rc) ? elapsed_in_this_state(rc) : 0)); -} - -/* Returns the current amount of backoff, in seconds. This is the amount of - * time after which the rconn will transition from BACKOFF to CONNECTING. */ -int -rconn_get_backoff(const struct rconn *rc) -{ - return rc->backoff; -} - -/* Returns the number of seconds spent in this state so far. */ -unsigned int -rconn_get_state_elapsed(const struct rconn *rc) -{ - return elapsed_in_this_state(rc); -} - -/* Returns 'rc''s current connection sequence number, a number that changes - * every time that 'rconn' connects or disconnects. */ -unsigned int -rconn_get_connection_seqno(const struct rconn *rc) -{ - return rc->seqno; -} - -/* Returns protocol statistical information. */ -/* TODO Zoltan: Temporarily removed when moving to OpenFlow 1.1 */ -/* -void -rconn_update_protocol_stat(struct rconn *rconn, - struct ofpstat *ofps_rcvd, - struct ofpstat *ofps_sent) -{ - struct vconn *vconn = rconn->vconn; - - if (vconn != NULL) { - rconn->ofps_rcvd.ofps_total += vconn->ofps_rcvd.ofps_total; - vconn->ofps_rcvd.ofps_total = 0; - rconn->ofps_rcvd.ofps_hello += vconn->ofps_rcvd.ofps_hello; - vconn->ofps_rcvd.ofps_hello = 0; - } - *ofps_rcvd = rconn->ofps_rcvd; - - if (vconn != NULL) { - rconn->ofps_sent.ofps_total += vconn->ofps_sent.ofps_total; - vconn->ofps_sent.ofps_total = 0; - rconn->ofps_sent.ofps_hello += vconn->ofps_sent.ofps_hello; - vconn->ofps_sent.ofps_hello = 0; - rconn->ofps_sent.ofps_error += vconn->ofps_sent.ofps_error; - vconn->ofps_sent.ofps_error = 0; - rconn->ofps_sent.ofps_error_type.hello_fail - += vconn->ofps_sent.ofps_error_type.hello_fail; - vconn->ofps_sent.ofps_error_type.hello_fail = 0; - rconn->ofps_sent.ofps_error_code.hf_incompat - += vconn->ofps_sent.ofps_error_code.hf_incompat; - vconn->ofps_sent.ofps_error_code.hf_incompat = 0; - } - *ofps_sent = rconn->ofps_sent; -} -*/ - -/* Tries to send a packet from 'rc''s send buffer. Returns 0 if successful, - * otherwise a positive errno value. */ -static int -try_send(struct rconn *rc) -{ - int retval = 0; - struct ofpbuf *next = rc->txq.head->next; - struct ofp_header *h = rc->txq.head->data; - int *n_queued = rc->txq.head->private_p; - /* TODO Zoltan: Temporarily removed when moving to OpenFlow 1.1 */ - /* ofpstat_inc_protocol_stat(&rc->ofps_sent, h); */ - rc->idle_echo_xid = h->xid; - retval = vconn_send(rc->vconn, rc->txq.head); - if (retval) { - rc->idle_echo_xid = 0; - if (retval != EAGAIN) { - disconnect(rc, retval); - } - return retval; - } - rc->packets_sent++; - if (n_queued) { - --*n_queued; - } - queue_advance_head(&rc->txq, next); - return 0; -} - -/* Disconnects 'rc'. 'error' is used only for logging purposes. If it is - * nonzero, then it should be EOF to indicate the connection was closed by the - * peer in a normal fashion or a positive errno value. */ -static void -disconnect(struct rconn *rc, int error) -{ - if (rc->reliable) { - time_t now = time_now(); - - if (rc->state & (S_CONNECTING | S_ACTIVE | S_IDLE)) { - if (error > 0) { - VLOG_WARN(LOG_MODULE, "%s: connection dropped (%s)", - rc->name, strerror(error)); - } else if (error == EOF) { - if (rc->reliable) { - VLOG_INFO(LOG_MODULE, "%s: connection closed by peer", rc->name); - } - } else { - VLOG_INFO(LOG_MODULE, "%s: connection dropped", rc->name); - } - vconn_close(rc->vconn); - rc->vconn = NULL; - flush_queue(rc); - } - - if (now >= rc->backoff_deadline) { - rc->backoff = 1; - } else { - rc->backoff = MIN(rc->max_backoff, MAX(1, 2 * rc->backoff)); - VLOG_INFO(LOG_MODULE, "%s: waiting %d seconds before reconnect", - rc->name, rc->backoff); - } - rc->backoff_deadline = now + rc->backoff; - state_transition(rc, S_BACKOFF); - if (now - rc->last_connected > 60) { - question_connectivity(rc); - } - } else { - rconn_disconnect(rc); - } -} - -/* Drops all the packets from 'rc''s send queue and decrements their queue - * counts. */ -static void -flush_queue(struct rconn *rc) -{ - if (!rc->txq.n) { - return; - } - while (rc->txq.n > 0) { - struct ofpbuf *b = queue_pop_head(&rc->txq); - int *n_queued = b->private_p; - if (n_queued) { - --*n_queued; - } - ofpbuf_delete(b); - } - poll_immediate_wake(); -} - -static unsigned int -elapsed_in_this_state(const struct rconn *rc) -{ - return time_now() - rc->state_entered; -} - -static unsigned int -timeout(const struct rconn *rc) -{ - switch (rc->state) { -#define STATE(NAME, VALUE) case S_##NAME: return timeout_##NAME(rc); - STATES -#undef STATE - default: - NOT_REACHED(); - } -} - -static bool -timed_out(const struct rconn *rc) -{ - return time_now() >= sat_add(rc->state_entered, timeout(rc)); -} - -static void -state_transition(struct rconn *rc, enum state state) -{ - rc->seqno += (rc->state == S_ACTIVE) != (state == S_ACTIVE); - if (is_connected_state(state) && !is_connected_state(rc->state)) { - rc->probably_admitted = false; - } - if (rconn_is_connected(rc)) { - rc->total_time_connected += elapsed_in_this_state(rc); - } - VLOG_DBG(LOG_MODULE, "%s: entering %s", rc->name, state_name(state)); - rc->state = state; - rc->state_entered = time_now(); -} - -static void -question_connectivity(struct rconn *rc) -{ - time_t now = time_now(); - if (now - rc->last_questioned > 60) { - rc->questionable_connectivity = true; - rc->last_questioned = now; - } -} - -static void -copy_to_monitor(struct rconn *rc, const struct ofpbuf *b) -{ - struct ofpbuf *clone = NULL; - int retval; - size_t i; - - for (i = 0; i < rc->n_monitors; ) { - struct vconn *vconn = rc->monitors[i]; - - if (!clone) { - clone = ofpbuf_clone(b); - } - retval = vconn_send(vconn, clone); - if (!retval) { - clone = NULL; - } else if (retval != EAGAIN) { - VLOG_DBG(LOG_MODULE, "%s: closing monitor connection to %s: %s", - rconn_get_name(rc), vconn_get_name(vconn), - strerror(retval)); - rc->monitors[i] = rc->monitors[--rc->n_monitors]; - continue; - } - i++; - } - ofpbuf_delete(clone); -} - -static bool -is_connected_state(enum state state) -{ - return (state & (S_ACTIVE | S_IDLE)) != 0; -} - -static bool -is_admitted_msg(const struct ofpbuf *b) -{ - struct ofp_header *oh = b->data; - - switch(oh->type) { - case OFPT_HELLO : - case OFPT_ECHO_REQUEST : - case OFPT_ECHO_REPLY : - case OFPT_EXPERIMENTER : - case OFPT_FEATURES_REQUEST : - case OFPT_GET_CONFIG_REQUEST : - case OFPT_SET_CONFIG : - case OFPT_FLOW_REMOVED : - case OFPT_PACKET_OUT : - case OFPT_FLOW_MOD : - case OFPT_GROUP_MOD : - case OFPT_PORT_MOD : - case OFPT_TABLE_MOD : - case OFPT_STATS_REQUEST : - case OFPT_BARRIER_REQUEST : - case OFPT_QUEUE_GET_CONFIG_REQUEST : { - return true; - } - default: { - return false; - } - } -} diff --git a/lib/vconn.h.bak b/lib/vconn.h.bak deleted file mode 100644 index f4f96a6c..00000000 --- a/lib/vconn.h.bak +++ /dev/null @@ -1,82 +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 VCONN_H -#define VCONN_H 1 - -#include -#include -#include - -struct ofpbuf; -struct flow; -struct ofp_header; -struct ofp_stats_reply; -struct pvconn; -struct vconn; - -void vconn_usage(bool active, bool passive, bool bootstrap); - -/* Active vconns: virtual connections to OpenFlow devices. */ -int vconn_open(const char *name, int min_version, struct vconn **); -void vconn_close(struct vconn *); -const char *vconn_get_name(const struct vconn *); -uint32_t vconn_get_ip(const struct vconn *); -bool vconn_is_reconnectable(const struct vconn *); -int vconn_connect(struct vconn *); -int vconn_recv(struct vconn *, struct ofpbuf **); -int vconn_send(struct vconn *, struct ofpbuf *); -int vconn_recv_xid(struct vconn *, uint32_t xid, struct ofpbuf **); -int vconn_transact(struct vconn *, struct ofpbuf *, struct ofpbuf **); - -int vconn_open_block(const char *name, int min_version, struct vconn **); -int vconn_send_block(struct vconn *, struct ofpbuf *); -int vconn_recv_block(struct vconn *, struct ofpbuf **); - -enum vconn_wait_type { - WAIT_CONNECT, - WAIT_RECV, - WAIT_SEND -}; -void vconn_wait(struct vconn *, enum vconn_wait_type); -void vconn_connect_wait(struct vconn *); -void vconn_recv_wait(struct vconn *); -void vconn_send_wait(struct vconn *); - -/* Passive vconns: virtual listeners for incoming OpenFlow connections. */ -int pvconn_open(const char *name, struct pvconn **); -void pvconn_close(struct pvconn *); -int pvconn_accept(struct pvconn *, int min_version, struct vconn **); -void pvconn_wait(struct pvconn *); - -#endif /* vconn.h */ diff --git a/utilities/dpctl.c.bak b/utilities/dpctl.c.bak deleted file mode 100644 index e57aaf03..00000000 --- a/utilities/dpctl.c.bak +++ /dev/null @@ -1,1980 +0,0 @@ -/* Copyright (c) 2011, TrafficLab, Ericsson Research, Hungary - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of the Ericsson Research nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * 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 HOLDER 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. - * - * - * Author: Zoltán Lajos Kis - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dpctl.h" -#include "oflib/ofl-messages.h" -#include "oflib/ofl-structs.h" -#include "oflib/ofl-actions.h" -#include "oflib/ofl-print.h" -#include "oflib/ofl.h" -#include "oflib-exp/ofl-exp.h" -#include "oflib-exp/ofl-exp-openflow.h" -#include "oflib/oxm-match.h" - -#include "command-line.h" -#include "compiler.h" -#include "dpif.h" -#include "openflow/nicira-ext.h" -#include "openflow/openflow-ext.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 "ipv6_util.h" - -#include "ofpstat.h" -#include "openflow/private-ext.h" - -#include "vlog.h" - -#define LOG_MODULE VLM_dpctl - - -// NOTE: the request and the barrier is sent with the same xid, -// so a vconn_receive_block will return with either the -// response, barrier resp., or the error -#define XID 0xf0ff00f0 - - -struct command { - char *name; - int min_args; - int max_args; - void (*handler)(struct vconn *vconn, int argc, char *argv[]); -}; - -static struct command all_commands[]; - -static void -usage(void) NO_RETURN; - -static void -parse_options(int argc, char *argv[]); - -static uint8_t mask_all[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - - - -static void -parse_flow_mod_args(char *str, struct ofl_msg_flow_mod *req); - -static void -parse_group_mod_args(char *str, struct ofl_msg_group_mod *req); - -static void -parse_bucket(char *str, struct ofl_bucket *b); - -static void -parse_flow_stat_args(char *str, struct ofl_msg_stats_request_flow *req); - -static void -parse_match(char *str, struct ofl_match_header **match); - -static void -parse_inst(char *str, struct ofl_instruction_header **inst); - -static void -parse_actions(char *str, size_t *acts_num, struct ofl_action_header ***acts); - -static void -parse_config(char *str, struct ofl_config *config); - -static void -parse_port_mod(char *str, struct ofl_msg_port_mod *msg); - -static void -parse_table_mod(char *str, struct ofl_msg_table_mod *msg); - - -static void -make_all_match(struct ofl_match_header **match); - - - - -static int -parse_port(char *str, uint32_t *port); - -static int -parse_queue(char *str, uint32_t *port); - -static int -parse_group(char *str, uint32_t *group); - -static int -parse_table(char *str, uint8_t *table); - -static int -parse_dl_addr(char *str, uint8_t *addr); - -static int -parse_nw_addr(char *str, uint32_t *addr); - -static int -parse_vlan_vid(char *str, uint16_t *vid); - - -static int -parse8(char *str, struct names8 *names, size_t names_num, uint8_t max, uint8_t *val); - -static int -parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val); - -static int -parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val); - - -static struct ofl_exp_msg dpctl_exp_msg = - {.pack = ofl_exp_msg_pack, - .unpack = ofl_exp_msg_unpack, - .free = ofl_exp_msg_free, - .to_string = ofl_exp_msg_to_string}; - -static struct ofl_exp dpctl_exp = - {.act = NULL, - .inst = NULL, - .match = NULL, - .stats = NULL, - .msg = &dpctl_exp_msg}; - - -static void -dpctl_transact(struct vconn *vconn, struct ofl_msg_header *req, - struct ofl_msg_header **repl) { - struct ofpbuf *ofpbufreq, *ofpbufrepl; - uint8_t *bufreq; - size_t bufreq_size; - int error; - - error = ofl_msg_pack(req, XID, &bufreq, &bufreq_size, &dpctl_exp); - if (error) { - ofp_fatal(0, "Error packing request."); - } - - ofpbufreq = ofpbuf_new(0); - ofpbuf_use(ofpbufreq, bufreq, bufreq_size); - ofpbuf_put_uninit(ofpbufreq, bufreq_size); - - error = vconn_transact(vconn, ofpbufreq, &ofpbufrepl); - if (error) { - ofp_fatal(0, "Error during transaction."); - } - - error = ofl_msg_unpack(ofpbufrepl->data, ofpbufrepl->size, repl, NULL /*xid_ptr*/, &dpctl_exp); - if (error) { - ofp_fatal(0, "Error unpacking reply."); - } - - /* NOTE: if unpack was successful, message takes over ownership of buffer's - * data. Rconn and vconn does not allocate headroom, so the ofpbuf - * wrapper can simply be deleted, keeping the data for the message. */ - ofpbufrepl->base = NULL; - ofpbufrepl->data = NULL; - ofpbuf_delete(ofpbufrepl); -} - -static void -dpctl_transact_and_print(struct vconn *vconn, struct ofl_msg_header *req, - struct ofl_msg_header **repl) { - struct ofl_msg_header *reply; - char *str; - - str = ofl_msg_to_string(req, &dpctl_exp); - printf("\nSENDING:\n%s\n\n", str); - free(str); - - dpctl_transact(vconn, req, &reply); - - str = ofl_msg_to_string(reply, &dpctl_exp); - printf("\nRECEIVED:\n%s\n\n", str); - free(str); - - if (repl != NULL) { - (*repl) = reply; - } else { - ofl_msg_free(reply, &dpctl_exp); - } -} - -static void -dpctl_barrier(struct vconn *vconn) { - struct ofl_msg_header *reply; - char *str; - - struct ofl_msg_header req = - {.type = OFPT_BARRIER_REQUEST}; - - dpctl_transact(vconn, &req, &reply); - - if (reply->type == OFPT_BARRIER_REPLY) { - str = ofl_msg_to_string(reply, &dpctl_exp); - printf("\nOK.\n\n"); - free(str); - } else { - str = ofl_msg_to_string(reply, &dpctl_exp); - printf("\nRECEIVED:\n%s\n\n", str); - free(str); - } - -} - -static void -dpctl_send(struct vconn *vconn, struct ofl_msg_header *msg) { - struct ofpbuf *ofpbuf; - uint8_t *buf; - size_t buf_size; - int error; - - error = ofl_msg_pack(msg, XID, &buf, &buf_size, &dpctl_exp); - if (error) { - ofp_fatal(0, "Error packing request."); - } - - ofpbuf = ofpbuf_new(0); - ofpbuf_use(ofpbuf, buf, buf_size); - ofpbuf_put_uninit(ofpbuf, buf_size); - - error = vconn_send_block(vconn, ofpbuf); - if (error) { - ofp_fatal(0, "Error during transaction."); - } - - dpctl_barrier(vconn); -} - -static void -dpctl_send_and_print(struct vconn *vconn, struct ofl_msg_header *msg) { - char *str; - - str = ofl_msg_to_string(msg, &dpctl_exp); - printf("\nSENDING:\n%s\n\n", str); - free(str); - - dpctl_send(vconn, msg); -} - -static void -ping(struct vconn *vconn, int argc, char *argv[]) { - uint16_t payload_size = 0; - size_t times = 0, i; - struct ofl_msg_echo *reply; - - struct ofl_msg_echo req = - {{.type = OFPT_ECHO_REQUEST}, - .data_length = 0, - .data = NULL}; - - if (argc > 0) { - times = atoi(argv[0]); - } - if (times == 0) { - times = 4; - } - if (argc > 1) { - payload_size = atoi(argv[1]); - } else { - payload_size = 1024; - } - if (payload_size > UINT16_MAX - sizeof(struct ofp_header)) { - ofp_fatal(0, "payload must be between 0 and %zu bytes.", UINT16_MAX - sizeof(struct ofp_header)); - } - - req.data_length = payload_size; - req.data = xmalloc(payload_size); - - for (i=0; idata_length) || - (memcmp(req.data, reply->data, req.data_length) != 0)) { - ofp_fatal(0, "Reply does not match request."); - } - - printf("%zu bytes from %s: time=%.1f ms\n", - (reply->data_length - sizeof(struct ofp_header)), - vconn_get_name(vconn), - (1000*(double)(end.tv_sec - start.tv_sec)) + (.001*(end.tv_usec - start.tv_usec))); - - } - - free(req.data); - ofl_msg_free((struct ofl_msg_header *)reply, &dpctl_exp); -} - -static void -monitor(struct vconn *vconn, int argc UNUSED, char *argv[] UNUSED) { - struct ofpbuf *buf; - struct ofl_msg_header *msg; - char *str; - int error; - - printf("MONITORING %s...\n\n", vconn_get_name(vconn)); - - for (;;) { - if (vconn_recv_block(vconn, &buf) == 0) { - - error = ofl_msg_unpack(buf->data, buf->size, &msg, NULL /*xid_ptr*/, &dpctl_exp); - if (error) { - ofp_fatal(0, "Error unpacking reply."); - } - - /* NOTE: if unpack was successful, message takes over ownership of buffer's - * data. Rconn and vconn does not allocate headroom, so the ofpbuf - * wrapper can simply be deleted, keeping the data for the message. */ - buf->base = NULL; - buf->data = NULL; - ofpbuf_delete(buf); - - str = ofl_msg_to_string(msg, &dpctl_exp); - printf("\nRECEIVED:\n%s\n\n", str); - free(str); - - ofl_msg_free(msg, &dpctl_exp); - } - } -} - -static void -features(struct vconn *vconn, int argc UNUSED, char *argv[] UNUSED) { - struct ofl_msg_header req = - {.type = OFPT_FEATURES_REQUEST}; - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -get_config(struct vconn *vconn, int argc UNUSED, char *argv[] UNUSED) { - struct ofl_msg_header req = - {.type = OFPT_GET_CONFIG_REQUEST}; - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -stats_desc(struct vconn *vconn, int argc UNUSED, char *argv[] UNUSED) { - struct ofl_msg_stats_request_header req = - {{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_DESC, .flags = 0x0000}; - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - -static void -stats_flow(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_flow req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_FLOW, .flags = 0x0000}, - .cookie = 0x0000000000000000ULL, - .cookie_mask = 0x0000000000000000ULL, - .table_id = 0xff, - .out_port = OFPP_ANY, - .out_group = OFPG_ANY, - .match = NULL}; - - if (argc > 0) { - parse_flow_stat_args(argv[0], &req); - } - if (argc > 1) { - parse_match(argv[1], &(req.match)); - } else { - make_all_match(&(req.match)); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - -static void -stats_aggr(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_flow req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_AGGREGATE, .flags = 0x0000}, - .cookie = 0x0000000000000000ULL, - .cookie_mask = 0x0000000000000000ULL, - .table_id = 0xff, - .out_port = OFPP_ANY, - .out_group = OFPG_ANY, - .match = NULL}; - - if (argc > 0) { - parse_flow_stat_args(argv[0], &req); - } - if (argc > 1) { - parse_match(argv[1], &(req.match)); - } else { - make_all_match(&(req.match)); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - -static void -stats_table(struct vconn *vconn, int argc UNUSED, char *argv[] UNUSED) { - struct ofl_msg_stats_request_header req = - {{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_TABLE, .flags = 0x0000}; - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -stats_port(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_port req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_PORT_STATS, .flags = 0x0000}, - .port_no = OFPP_ANY}; - - if (argc > 0 && parse_port(argv[0], &req.port_no)) { - ofp_fatal(0, "Error parsing port: %s.", argv[0]); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -stats_queue(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_queue req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_QUEUE, .flags = 0x0000}, - .port_no = OFPP_ANY, - .queue_id = OFPQ_ALL}; - - if (argc > 0 && parse_port(argv[0], &req.port_no)) { - ofp_fatal(0, "Error parsing port: %s.", argv[0]); - } - if (argc > 1 && parse_queue(argv[1], &req.queue_id)) { - ofp_fatal(0, "Error parsing queue: %s.", argv[1]); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -stats_group(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_group req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_GROUP, .flags = 0x0000}, - .group_id = OFPG_ALL}; - - if (argc > 0 && parse_group(argv[0], &req.group_id)) { - ofp_fatal(0, "Error parsing group: %s.", argv[0]); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - -static void -stats_group_desc(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_stats_request_group req = - {{{.type = OFPT_MULTIPART_REQUEST}, - .type = OFPMP_GROUP_DESC, .flags = 0x0000}, - .group_id = OFPG_ALL}; - - if (argc > 0 && parse_group(argv[0], &req.group_id)) { - ofp_fatal(0, "Error parsing group: %s.", argv[0]); - } - - dpctl_transact_and_print(vconn, (struct ofl_msg_header *)&req, NULL); -} - - - - - -static void -set_config(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_msg_set_config msg = - {{.type = OFPT_SET_CONFIG}, - .config = NULL}; - - msg.config = xmalloc(sizeof(struct ofl_config)); - msg.config->flags = OFPC_FRAG_NORMAL; - msg.config->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN; - - parse_config(argv[0], msg.config); - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -flow_mod(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_flow_mod msg = - {{.type = OFPT_FLOW_MOD}, - .cookie = 0x0000000000000000ULL, - .cookie_mask = 0x0000000000000000ULL, - .table_id = 0xff, - .command = OFPFC_ADD, - .idle_timeout = OFP_FLOW_PERMANENT, - .hard_timeout = OFP_FLOW_PERMANENT, - .priority = OFP_DEFAULT_PRIORITY, - .buffer_id = 0xffffffff, - .out_port = OFPP_ANY, - .out_group = OFPG_ANY, - .flags = 0x0000, - .match = NULL, - .instructions_num = 0, - .instructions = NULL}; - - parse_flow_mod_args(argv[0], &msg); - - if (argc > 1) { - size_t i; - size_t inst_num = argc - 2; - parse_match(argv[1], &(msg.match)); - - msg.instructions_num = inst_num; - msg.instructions = xmalloc(sizeof(struct ofl_instrcution_header *) * inst_num); - - for (i=0; i < inst_num; i++) { - parse_inst(argv[2+i], &(msg.instructions[i])); - } - } else { - make_all_match(&(msg.match)); - } - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -group_mod(struct vconn *vconn, int argc, char *argv[]) { - struct ofl_msg_group_mod msg = - {{.type = OFPT_GROUP_MOD}, - .command = OFPGC_ADD, - .type = OFPGT_ALL, - .group_id = OFPG_ALL, - .buckets_num = 0, - .buckets = NULL}; - - parse_group_mod_args(argv[0], &msg); - - if (argc > 1) { - size_t i; - size_t buckets_num = (argc - 1) / 2; - - msg.buckets_num = buckets_num; - msg.buckets = xmalloc(sizeof(struct ofl_bucket *) * buckets_num); - - for (i=0; i < buckets_num; i++) { - msg.buckets[i] = xmalloc(sizeof(struct ofl_bucket)); - msg.buckets[i]->weight = 0; - msg.buckets[i]->watch_port = OFPP_ANY; - msg.buckets[i]->watch_group = OFPG_ANY; - msg.buckets[i]->actions_num = 0; - msg.buckets[i]->actions = NULL; - - parse_bucket(argv[i*2+1], msg.buckets[i]); - parse_actions(argv[i*2+2], &(msg.buckets[i]->actions_num), &(msg.buckets[i]->actions)); - } - } - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -port_mod(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_msg_port_mod msg = - {{.type = OFPT_PORT_MOD}, - .port_no = OFPP_ANY, - .config = 0x00000000, - .mask = 0x00000000, - .advertise = 0x00000000 - }; - memcpy(msg.hw_addr, mask_all, OFP_ETH_ALEN); - - parse_port_mod(argv[0], &msg); - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -table_mod(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_msg_table_mod msg = - {{.type = OFPT_TABLE_MOD}, - .table_id = 0xff, - .config = 0x00}; - - parse_table_mod(argv[0], &msg); - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -queue_get_config(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_msg_queue_get_config_request msg = - {{.type = OFPT_QUEUE_GET_CONFIG_REQUEST}, - .port = OFPP_ALL}; - - if (parse_port(argv[0], &msg.port)) { - ofp_fatal(0, "Error parsing queue_get_config port: %s.", argv[0]); - } - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -set_desc(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_exp_openflow_msg_set_dp_desc msg = - {{{{.type = OFPT_EXPERIMENTER}, - .experimenter_id = OPENFLOW_VENDOR_ID}, - .type = OFP_EXT_SET_DESC}, - .dp_desc = argv[0]}; - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -queue_mod(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_packet_queue *pq; - struct ofl_queue_prop_min_rate *p; - - struct ofl_exp_openflow_msg_queue msg = - {{{{.type = OFPT_EXPERIMENTER}, - .experimenter_id = OPENFLOW_VENDOR_ID}, - .type = OFP_EXT_QUEUE_MODIFY}, - .port_id = OFPP_ANY, - .queue = NULL}; - - if (parse_port(argv[0], &msg.port_id)) { - ofp_fatal(0, "Error parsing queue_mod port: %s.", argv[0]); - } - - pq = xmalloc(sizeof(struct ofl_packet_queue)); - msg.queue = pq; - if (parse_queue(argv[1], &pq->queue_id)) { - ofp_fatal(0, "Error parsing queue_mod queue: %s.", argv[1]); - } - - pq->properties_num = 1; - pq->properties = xmalloc(sizeof(struct ofl_queue_prop_header *)); - - p = xmalloc(sizeof(struct ofl_queue_prop_min_rate)); - pq->properties[0] = (struct ofl_queue_prop_header *)p; - p->header.type = OFPQT_MIN_RATE; - - if (parse16(argv[2], NULL,0, UINT16_MAX, &p->rate)) { - ofp_fatal(0, "Error parsing queue_mod bw: %s.", argv[2]); - } - - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - - - -static void -queue_del(struct vconn *vconn, int argc UNUSED, char *argv[]) { - struct ofl_packet_queue *pq; - - struct ofl_exp_openflow_msg_queue msg = - {{{{.type = OFPT_EXPERIMENTER}, - .experimenter_id = OPENFLOW_VENDOR_ID}, - .type = OFP_EXT_QUEUE_DELETE}, - .port_id = OFPP_ANY, - .queue = NULL}; - - if (parse_port(argv[0], &msg.port_id)) { - ofp_fatal(0, "Error parsing queue_mod port: %s.", argv[0]); - } - - pq = xmalloc(sizeof(struct ofl_packet_queue)); - msg.queue = pq; - if (parse_queue(argv[1], &pq->queue_id)) { - ofp_fatal(0, "Error parsing queue_mod queue: %s.", argv[1]); - } - - pq->properties_num = 0; - pq->properties = NULL; - - dpctl_send_and_print(vconn, (struct ofl_msg_header *)&msg); -} - -static struct command all_commands[] = { - {"ping", 0, 2, ping}, - {"monitor", 0, 0, monitor}, - - {"features", 0, 0, features }, - {"get-config", 0, 0, get_config}, - {"stats-desc", 0, 0, stats_desc }, - {"stats-flow", 0, 2, stats_flow}, - {"stats-aggr", 0, 2, stats_aggr}, - {"stats-table", 0, 0, stats_table }, - {"stats-port", 0, 1, stats_port }, - {"stats-queue", 0, 2, stats_queue }, - {"stats-group", 0, 1, stats_group }, - {"stats-group-desc", 0, 1, stats_group_desc }, - - {"set-config", 1, 1, set_config}, - {"flow-mod", 1, 7/*+1 for each inst type*/, flow_mod }, - {"group-mod", 1, UINT8_MAX, group_mod }, - {"port-mod", 1, 1, port_mod }, - {"table-mod", 1, 1, table_mod }, - {"queue-get-config", 1, 1, queue_get_config}, - - {"set-desc", 1, 1, set_desc}, - {"queue-mod", 3, 3, queue_mod}, - {"queue-del", 2, 2, queue_del} -}; - - -int main(int argc, char *argv[]) -{ - struct command *p; - struct vconn *vconn; - size_t i; - int error; - - set_program_name(argv[0]); - time_init(); - vlog_init(); - parse_options(argc, argv); - signal(SIGPIPE, SIG_IGN); - - argc -= optind; - argv += optind; - if (argc < 1) - ofp_fatal(0, "missing SWITCH; use --help for help"); - if (argc < 2) - ofp_fatal(0, "missing COMMAND; use --help for help"); - - error = vconn_open_block(argv[0], OFP_VERSION, &vconn); - if (error) { - ofp_fatal(error, "Error connecting to switch %s.", argv[0]); - } - argc -= 1; - argv += 1; - - for (i=0; iname, argv[0]) == 0) { - argc -= 1; - argv += 1; - if (argc < p->min_args) - ofp_fatal(0, "'%s' command requires at least %d arguments", - p->name, p->min_args); - else if (argc > p->max_args) - ofp_fatal(0, "'%s' command takes at most %d arguments", - p->name, p->max_args); - else { - p->handler(vconn, argc, argv); - if (ferror(stdout)) { - ofp_fatal(0, "write to stdout failed"); - } - if (ferror(stderr)) { - ofp_fatal(0, "write to stderr failed"); - } - vconn_close(vconn); - exit(0); - } - } - } - ofp_fatal(0, "unknown command '%s'; use --help for help", argv[0]); - vconn_close(vconn); - return 0; -} - -static void -parse_options(int argc, char *argv[]) -{ - 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); - - 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; - - 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] SWITCH COMMAND [ARG...]\n" - " SWITCH ping [N] [B] latency of B-byte echos N times\n" - " SWITCH monitor monitors packets from the switch\n" - "\n" - " SWITCH features show basic information\n" - " SWITCH get-config get switch configuration\n" - " SWITCH stats-desc print switch description\n" - " SWITCH stats-flow [ARG [MATCH]] print flow stats\n" - " SWITCH stats-aggr [ARG [MATCH]] print flow aggregate stats\n" - " SWITCH stats-table print table stats\n" - " SWITCH stats-port [PORT] print port statistics\n" - " SWITCH stats-queue [PORT [QUEUE]] print queue statistics\n" - " SWITCH stats-group [GROUP] print group statistics\n" - " SWITCH stats-group-desc [GROUP] print group desc statistics\n" - "\n" - " SWITCH set-config ARG set switch configuration\n" - " SWITCH flow-mod ARG [MATCH [INST...]] send flow_mod message\n" - " SWITCH group-mod ARG [BUCARG ACT...] send group_mod message\n" - " SWITCH port-mod ARG send port_mod message\n" - " SWITCH table-mod ARG send table_mod message\n" - " SWITCH queue-get-config PORT send queue_get_config message\n" - "\n" - "OpenFlow extensions\n" - " SWITCH set-desc DESC sets the DP description\n" - " SWITCH queue-mod PORT QUEUE BW adds/modifies queue\n" - " SWITCH queue-del PORT QUEUE deletes queue\n" - "\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 -parse_match(char *str, struct ofl_match_header **match) { - // TODO parse masks - char *token, *saveptr = NULL; - struct ofl_match *m = xmalloc(sizeof(struct ofl_match)); - ofl_structs_match_init(m); - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, "apply", strlen("apply")) == 0 ) { - break; - } - /* In_port */ - if (strncmp(token, MATCH_IN_PORT KEY_VAL, strlen(MATCH_IN_PORT KEY_VAL)) == 0) { - uint32_t in_port; - if (parse_port(token + strlen(MATCH_IN_PORT KEY_VAL), &in_port)) { - ofp_fatal(0, "Error parsing port: %s.", token); - } - else ofl_structs_match_put32(m,OXM_OF_IN_PORT,in_port); - continue; - } - - /* Ethernet Address*/ - if (strncmp(token, MATCH_DL_SRC KEY_VAL, strlen(MATCH_DL_SRC KEY_VAL)) == 0) { - uint8_t eth_src[6]; - if (parse_dl_addr(token + strlen(MATCH_DL_SRC KEY_VAL), eth_src)) { - ofp_fatal(0, "Error parsing dl_src: %s.", token); - } - else ofl_structs_match_put_eth(m,OXM_OF_ETH_SRC,eth_src); - continue; - } - if (strncmp(token, MATCH_DL_DST KEY_VAL, strlen(MATCH_DL_DST KEY_VAL)) == 0) { - uint8_t eth_dst[6]; - if (parse_dl_addr(token + strlen(MATCH_DL_DST KEY_VAL), eth_dst)) { - ofp_fatal(0, "Error parsing dl_dst: %s.", token); - } - else ofl_structs_match_put_eth(m,OXM_OF_ETH_DST,eth_dst); - continue; - } - - /* ARP */ - if (strncmp(token, MATCH_ARP_SHA KEY_VAL, strlen(MATCH_ARP_SHA KEY_VAL)) == 0) { - uint8_t arp_sha[6]; - if (parse_dl_addr(token + strlen(MATCH_DL_SRC KEY_VAL), arp_sha)) { - ofp_fatal(0, "Error parsing arp_sha: %s.", token); - } - else ofl_structs_match_put_eth(m, OXM_OF_ARP_SHA, arp_sha); - continue; - } - if (strncmp(token, MATCH_ARP_THA KEY_VAL, strlen(MATCH_ARP_THA KEY_VAL)) == 0) { - uint8_t arp_tha[6]; - if (parse_dl_addr(token + strlen(MATCH_ARP_THA KEY_VAL), arp_tha)) { - ofp_fatal(0, "Error parsing arp_tha %s.", token); - } - else ofl_structs_match_put_eth(m,OXM_OF_ARP_THA, arp_tha); - continue; - } - if (strncmp(token, MATCH_ARP_OP KEY_VAL, strlen(MATCH_ARP_OP KEY_VAL)) == 0) { - uint8_t arp_op; - if (parse8(token + strlen(MATCH_DL_VLAN_PCP KEY_VAL), NULL, 0, 0x7, &arp_op)) { - ofp_fatal(0, "Error parsing arp_op: %s.", token); - } else - ofl_structs_match_put8(m, OXM_OF_ARP_OP, arp_op); - continue; - } - - /* VLAN */ - if (strncmp(token, MATCH_DL_VLAN KEY_VAL, strlen(MATCH_DL_VLAN KEY_VAL)) == 0) { - uint16_t dl_vlan; - if (parse_vlan_vid(token + strlen(MATCH_DL_VLAN KEY_VAL), &dl_vlan)) { - ofp_fatal(0, "Error parsing vlan label: %s.", token); - } - else ofl_structs_match_put16(m,OXM_OF_VLAN_VID, dl_vlan); - continue; - } - if (strncmp(token, MATCH_DL_VLAN_PCP KEY_VAL, strlen(MATCH_DL_VLAN_PCP KEY_VAL)) == 0) { - uint8_t pcp; - if (parse8(token + strlen(MATCH_DL_VLAN_PCP KEY_VAL), NULL, 0, 0x7, &pcp)) { - ofp_fatal(0, "Error parsing vlan pcp: %s.", token); - } else - ofl_structs_match_put8(m, OXM_OF_VLAN_PCP, pcp); - continue; - } - - /* Eth Type */ - if (strncmp(token, MATCH_DL_TYPE KEY_VAL, strlen(MATCH_DL_TYPE KEY_VAL)) == 0) { - uint16_t dl_type; - if (parse16(token + strlen(MATCH_DL_TYPE KEY_VAL), NULL, 0, 0xffff, &dl_type)) { - ofp_fatal(0, "Error parsing eth_type: %s.", token); - } - else - ofl_structs_match_put16(m, OXM_OF_ETH_TYPE,dl_type); - continue; - } - - /* IP */ - if (strncmp(token, MATCH_IP_ECN, strlen(MATCH_IP_ECN KEY_VAL)) == 0) { - uint8_t ip_ecn; - if (parse8(token + strlen(MATCH_IP_ECN KEY_VAL), NULL, 0, 0x3f, &ip_ecn)) { - ofp_fatal(0, "Error parsing nw_tos: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_IP_ECN, ip_ecn); - continue; - } - if (strncmp(token, MATCH_IP_DSCP, strlen(MATCH_IP_DSCP KEY_VAL)) == 0) { - uint8_t ip_dscp; - if (parse8(token + strlen(MATCH_IP_DSCP KEY_VAL), NULL, 0, 0x3f, &ip_dscp)) { - ofp_fatal(0, "Error parsing nw_tos: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_IP_DSCP, ip_dscp); - continue; - } - if (strncmp(token, MATCH_NW_PROTO KEY_VAL, strlen(MATCH_NW_PROTO KEY_VAL)) == 0) { - uint8_t nw_proto; - if (parse8(token + strlen(MATCH_NW_PROTO KEY_VAL), NULL, 0, 0xff, &nw_proto)) { - ofp_fatal(0, "Error parsing ip_proto: %s.", token); - } - else ofl_structs_match_put8(m,OXM_OF_IP_PROTO, nw_proto); - continue; - } - if (strncmp(token, MATCH_NW_SRC KEY_VAL, strlen(MATCH_NW_SRC KEY_VAL)) == 0) { - uint32_t nw_src; - if (parse_nw_addr(token + strlen(MATCH_NW_SRC KEY_VAL), &(nw_src))) { - ofp_fatal(0, "Error parsing ip_src: %s.", token); - } - else ofl_structs_match_put32(m, OXM_OF_IPV4_SRC,nw_src); - continue; - } - if (strncmp(token, MATCH_NW_DST KEY_VAL, strlen(MATCH_NW_DST KEY_VAL)) == 0) { - uint32_t nw_dst; - if (parse_nw_addr(token + strlen(MATCH_NW_DST KEY_VAL), &nw_dst)) { - ofp_fatal(0, "Error parsing ip_dst: %s.", token); - } - else ofl_structs_match_put32(m, OXM_OF_IPV4_DST,nw_dst); - continue; - } - - /* ICMP */ - if (strncmp(token, MATCH_ICMPV4_CODE, strlen(MATCH_ICMPV4_CODE KEY_VAL)) == 0) { - uint8_t icmpv4_code; - if (parse8(token + strlen(MATCH_ICMPV4_CODE KEY_VAL), NULL, 0, 0x3f, &icmpv4_code)) { - ofp_fatal(0, "Error parsing icmpv4_code: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_ICMPV4_CODE, icmpv4_code); - continue; - } - if (strncmp(token, MATCH_ICMPV4_TYPE, strlen(MATCH_ICMPV4_TYPE KEY_VAL)) == 0) { - uint8_t icmpv4_type; - if (parse8(token + strlen(MATCH_ICMPV4_TYPE KEY_VAL), NULL, 0, 0x3f, &icmpv4_type)) { - ofp_fatal(0, "Error parsing icmpv4_type: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_ICMPV4_CODE, icmpv4_type); - continue; - } - - /* TCP */ - if (strncmp(token, MATCH_TP_SRC KEY_VAL, strlen(MATCH_TP_SRC KEY_VAL)) == 0) { - uint16_t tp_src; - if (parse16(token + strlen(MATCH_TP_SRC KEY_VAL), NULL, 0, 0xffff, &tp_src)) { - ofp_fatal(0, "Error parsing tcp_src: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_TCP_SRC,tp_src); - continue; - } - if (strncmp(token, MATCH_TP_DST KEY_VAL, strlen(MATCH_TP_DST KEY_VAL)) == 0) { - uint16_t tp_dst; - if (parse16(token + strlen(MATCH_TP_DST KEY_VAL), NULL, 0, 0xffff, &tp_dst)) { - ofp_fatal(0, "Error parsing tcp_dst: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_TCP_DST,tp_dst); - continue; - } - - /*UDP */ - if (strncmp(token, MATCH_UDP_SRC KEY_VAL, strlen(MATCH_UDP_SRC KEY_VAL)) == 0) { - uint16_t udp_src; - if (parse16(token + strlen(MATCH_UDP_SRC KEY_VAL), NULL, 0, 0xffff, &udp_src)) { - ofp_fatal(0, "Error parsing udp_src: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_UDP_SRC,udp_src); - continue; - } - if (strncmp(token, MATCH_UDP_DST KEY_VAL, strlen(MATCH_UDP_DST KEY_VAL)) == 0) { - uint16_t udp_dst; - if (parse16(token + strlen(MATCH_UDP_DST KEY_VAL), NULL, 0, 0xffff, &udp_dst)) { - ofp_fatal(0, "Error parsing udp_dst: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_UDP_DST,udp_dst); - continue; - } - - /*SCTP*/ - if (strncmp(token, MATCH_SCTP_SRC KEY_VAL, strlen(MATCH_SCTP_SRC KEY_VAL)) == 0) { - uint16_t sctp_src; - if (parse16(token + strlen(MATCH_SCTP_SRC KEY_VAL), NULL, 0, 0xffff, &sctp_src)) { - ofp_fatal(0, "Error parsing sctp_src: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_SCTP_SRC,sctp_src); - continue; - } - if (strncmp(token, MATCH_SCTP_DST KEY_VAL, strlen(MATCH_SCTP_DST KEY_VAL)) == 0) { - uint16_t sctp_dst; - if (parse16(token + strlen(MATCH_SCTP_DST KEY_VAL), NULL, 0, 0xffff, &sctp_dst)) { - ofp_fatal(0, "Error parsing sctp_dst: %s.", token); - } - else ofl_structs_match_put16(m, OXM_OF_SCTP_DST,sctp_dst); - continue; - } - - /* MPLS */ - if (strncmp(token, MATCH_MPLS_LABEL KEY_VAL, strlen(MATCH_MPLS_LABEL KEY_VAL)) == 0) { - uint32_t mpls_label; - if (parse32(token + strlen(MATCH_MPLS_LABEL KEY_VAL), NULL, 0, 0xfffff, &mpls_label)) { - ofp_fatal(0, "Error parsing mpls_label: %s.", token); - } - else ofl_structs_match_put32(m,OXM_OF_MPLS_LABEL,mpls_label); - } - if (strncmp(token, MATCH_MPLS_TC KEY_VAL, strlen(MATCH_MPLS_TC KEY_VAL)) == 0) { - uint8_t mpls_tc; - if (parse8(token + strlen(MATCH_MPLS_TC KEY_VAL), NULL, 0, 0x07, &mpls_tc)) { - ofp_fatal(0, "Error parsing mpls_tc: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_MPLS_TC, mpls_tc); - continue; - } - - /* IPv6 */ - if (strncmp(token, MATCH_NW_SRC_IPV6 KEY_VAL , strlen(MATCH_NW_SRC_IPV6 KEY_VAL)) == 0) { - struct in6_addr addr, mask; - if (str_to_ipv6(token + strlen(MATCH_NW_DST_IPV6)+1, &addr, &mask) < 0) { - ofp_fatal(0, "Error parsing nw_src_ipv6: %s.", token); - } - else { - ofl_structs_match_put_ipv6(m, OXM_OF_IPV6_SRC, addr.s6_addr); - } - continue; - } - if (strncmp(token, MATCH_NW_DST_IPV6 KEY_VAL , strlen(MATCH_NW_DST_IPV6 KEY_VAL)) == 0) { - struct in6_addr addr, mask; - if (str_to_ipv6(token + strlen(MATCH_NW_DST_IPV6)+1, &addr, &mask) < 0) { - ofp_fatal(0, "Error parsing nw_src_ipv6: %s.", token); - } - else { - ofl_structs_match_put_ipv6(m, OXM_OF_IPV6_DST, addr.s6_addr); - } - continue; - } - if (strncmp(token, MATCH_IPV6_FLABEL KEY_VAL, strlen(MATCH_IPV6_FLABEL KEY_VAL)) == 0) { - uint32_t ipv6_label; - if (parse32(token + strlen(MATCH_IPV6_FLABEL KEY_VAL), NULL, 0, 0xfffff, &ipv6_label)) { - ofp_fatal(0, "Error parsing ipv6_label: %s.", token); - } - else ofl_structs_match_put32(m,OXM_OF_IPV6_FLABEL, ipv6_label); - } - - /* ICMPv6 */ - if (strncmp(token, MATCH_ICMPV6_CODE, strlen(MATCH_ICMPV6_CODE KEY_VAL)) == 0) { - uint8_t icmpv6_code; - if (parse8(token + strlen(MATCH_ICMPV6_CODE KEY_VAL), NULL, 0, 0x3f, &icmpv6_code)) { - ofp_fatal(0, "Error parsing icmpv6_code: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_ICMPV6_CODE, icmpv6_code); - continue; - } - if (strncmp(token, MATCH_ICMPV6_TYPE, strlen(MATCH_ICMPV6_TYPE KEY_VAL)) == 0) { - uint8_t icmpv6_type; - if (parse8(token + strlen(MATCH_ICMPV6_TYPE KEY_VAL), NULL, 0, 0x3f, &icmpv6_type)) { - ofp_fatal(0, "Error parsing icmpv6_type: %s.", token); - } - else - ofl_structs_match_put8(m, OXM_OF_ICMPV6_CODE, icmpv6_type); - continue; - } - - /* IPv6 ND */ - if (strncmp(token, MATCH_IPV6_ND_TARGET KEY_VAL , strlen(MATCH_IPV6_ND_TARGET KEY_VAL)) == 0) { - struct in6_addr addr, mask; - if (str_to_ipv6(token + strlen(MATCH_IPV6_ND_TARGET)+1, &addr, &mask) < 0) { - ofp_fatal(0, "Error parsing ipv6_nd_target %s.", token); - } - else { - ofl_structs_match_put_ipv6(m, OXM_OF_IPV6_ND_TARGET, addr.s6_addr); - } - continue; - } - if (strncmp(token, MATCH_IPV6_ND_SLL KEY_VAL, strlen(MATCH_IPV6_ND_SLL KEY_VAL)) == 0) { - uint8_t eth_src[6]; - if (parse_dl_addr(token + strlen(MATCH_IPV6_ND_SLL KEY_VAL), eth_src)) { - ofp_fatal(0, "Error parsing ipv6_nd_sll: %s.", token); - } - else ofl_structs_match_put_eth(m,OXM_OF_IPV6_ND_SLL, eth_src); - continue; - } - if (strncmp(token, MATCH_IPV6_ND_TLL KEY_VAL, strlen(MATCH_IPV6_ND_TLL KEY_VAL)) == 0) { - uint8_t eth_dst[6]; - if (parse_dl_addr(token + strlen(MATCH_IPV6_ND_TLL KEY_VAL), eth_dst)) { - ofp_fatal(0, "Error parsing ipv_nd_tll: %s.", token); - } - else ofl_structs_match_put_eth(m, OXM_OF_IPV6_ND_TLL,eth_dst); - continue; - } - - /* Metadata */ - if (strncmp(token, MATCH_METADATA KEY_VAL, strlen(MATCH_METADATA KEY_VAL)) == 0) { - uint64_t metadata; - if (sscanf(token, MATCH_METADATA KEY_VAL "0x%"SCNx64"", (&metadata))) { - ofp_fatal(0, "Error parsing %s: %s.", MATCH_METADATA, token); - } - else ofl_structs_match_put64(m, OXM_OF_METADATA, metadata); - continue; - } - ofp_fatal(0, "Error parsing match arg: %s.", token); - } - - (*match) = (struct ofl_match_header *)m; -} - -static int -parse_set_field(char *token, struct ofl_action_set_field *act) { - - - if (strncmp(token, MATCH_DL_SRC KEY_VAL, strlen(MATCH_DL_SRC KEY_VAL)) == 0) { - uint8_t* dl_src = xmalloc(6); - if (parse_dl_addr(token + strlen(MATCH_DL_SRC KEY_VAL), dl_src)) { - ofp_fatal(0, "Error parsing dl_src: %s.", token); - }else{ - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_ETH_SRC; - act->field->value = (uint8_t*) dl_src; - } - return 0; - } - if (strncmp(token, MATCH_DL_DST KEY_VAL, strlen(MATCH_DL_DST KEY_VAL)) == 0) { - uint8_t* dl_dst = xmalloc(6); - if (parse_dl_addr(token + strlen(MATCH_DL_SRC KEY_VAL), dl_dst)) { - ofp_fatal(0, "Error parsing dl_dst: %s.", token); - }else{ - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_ETH_DST; - act->field->value = (uint8_t*) dl_dst; - } - } - if (strncmp(token, MATCH_DL_VLAN KEY_VAL, strlen(MATCH_DL_VLAN KEY_VAL)) == 0) { - uint16_t *dl_vlan = malloc(sizeof(uint16_t)); - if (parse_vlan_vid(token + strlen(MATCH_DL_VLAN KEY_VAL), dl_vlan)) { - ofp_fatal(0, "Error parsing vlan label: %s.", token); - } - else { - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_VLAN_VID; - act->field->value = (uint8_t*) dl_vlan; - } - return 0; - } - if (strncmp(token, MATCH_DL_VLAN_PCP KEY_VAL, strlen(MATCH_DL_VLAN_PCP KEY_VAL)) == 0) { - uint8_t* vlan_pcp = malloc(sizeof(uint8_t)); - if (parse8(token + strlen(MATCH_DL_VLAN_PCP KEY_VAL), NULL, 0, 0x7, vlan_pcp)) { - ofp_fatal(0, "Error parsing vlan pcp: %s.", token); - } - else{ - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_VLAN_PCP; - act->field->value = (uint8_t*) vlan_pcp; - } - return 0; - } - if (strncmp(token, MATCH_DL_TYPE KEY_VAL, strlen(MATCH_DL_TYPE KEY_VAL)) == 0) { - uint16_t* dl_type = xmalloc(sizeof(uint16_t)); - if (parse16(token + strlen(MATCH_DL_TYPE KEY_VAL), NULL, 0, 0xffff, dl_type)) { - ofp_fatal(0, "Error parsing dl_type: %s.", token); - } - else { - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_ETH_TYPE; - act->field->value = (uint8_t*) dl_type; - } - return 0; - } - if (strncmp(token, MATCH_NW_SRC KEY_VAL, strlen(MATCH_NW_SRC KEY_VAL)) == 0) { - uint32_t* nw_src = malloc(sizeof(uint32_t)); - if (parse_nw_addr(token + strlen(MATCH_NW_SRC KEY_VAL), nw_src)) { - ofp_fatal(0, "Error parsing ip_src: %s.", token); - } - else { - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_IPV4_SRC; - act->field->value = (uint8_t*) nw_src; - } - return 0; - } - if (strncmp(token, MATCH_NW_DST KEY_VAL, strlen(MATCH_NW_DST KEY_VAL)) == 0) { - uint32_t * nw_dst = malloc(sizeof(uint32_t)); - if (parse_nw_addr(token + strlen(MATCH_NW_DST KEY_VAL), nw_dst)) { - ofp_fatal(0, "Error parsing ip_dst: %s.", token); - } - else { - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_IPV4_DST; - act->field->value = (uint8_t*) nw_dst; - } - return 0; - } - if (strncmp(token, MATCH_TP_SRC KEY_VAL, strlen(MATCH_TP_SRC KEY_VAL)) == 0) { - uint16_t* tp_src = xmalloc(2); - if (parse16(token+ strlen(MATCH_TP_SRC KEY_VAL), NULL, 0, 0xffff, tp_src)) { - ofp_fatal(0, "Error parsing tcp_src: %s.", token); - }else{ - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_TCP_SRC; - act->field->value = (uint8_t*) tp_src; - } - return 0; - } - if (strncmp(token, MATCH_TP_DST KEY_VAL, strlen(MATCH_TP_DST KEY_VAL)) == 0) { - uint16_t* tp_dst = xmalloc(2); - if (parse16(token + strlen(MATCH_TP_SRC KEY_VAL), NULL, 0, 0xffff, tp_dst)) { - ofp_fatal(0, "Error parsing tcp_src: %s.", token); - }else{ - act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); - act->field->header = OXM_OF_TCP_DST; - act->field->value = (uint8_t*) tp_dst; - } - return 0; - } - ofp_fatal(0, "Error parsing set_field arg: %s.", token); -} - -static void -make_all_match(struct ofl_match_header **match) { - struct ofl_match *m = xmalloc(sizeof(struct ofl_match)); - - ofl_structs_match_init(m); - - (*match) = (struct ofl_match_header *)m; -} - - -static void -parse_action(uint16_t type, char *str, struct ofl_action_header **act) { - switch (type) { - case (OFPAT_OUTPUT): { - char *token, *saveptr = NULL; - struct ofl_action_output *a = xmalloc(sizeof(struct ofl_action_output)); - - token = strtok_r(str, KEY_VAL2, &saveptr); - if (parse_port(token, &(a->port))) { - ofp_fatal(0, "Error parsing port in output action: %s.", str); - } - token = strtok_r(NULL, KEY_VAL2, &saveptr); - if (token == NULL) { - a->max_len = 0; - } else { - if (parse16(token, NULL, 0, 0xffff - sizeof(struct ofp_header), &(a->max_len))) { - ofp_fatal(0, "Error parsing max_len in output action: %s.", str); - } - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_SET_FIELD):{ - struct ofl_action_set_field *a = xmalloc(sizeof (struct ofl_action_set_field)); - if (parse_set_field(str, a)) { - ofp_fatal(0, "Error parsing field in set_field action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_COPY_TTL_OUT): - case (OFPAT_COPY_TTL_IN): { - struct ofl_action_header *a = xmalloc(sizeof(struct ofl_action_header)); - (*act) = a; - break; - } - case (OFPAT_SET_MPLS_TTL): { - struct ofl_action_mpls_ttl *a = xmalloc(sizeof(struct ofl_action_mpls_ttl)); - if (parse8(str, NULL, 0, 255, &(a->mpls_ttl))) { - ofp_fatal(0, "Error parsing ttl in mpls_ttl action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_DEC_MPLS_TTL): { - struct ofl_action_header *a = xmalloc(sizeof(struct ofl_action_header)); - (*act) = a; - break; - } - case (OFPAT_PUSH_VLAN): - case (OFPAT_PUSH_MPLS): { - struct ofl_action_push *a = xmalloc(sizeof(struct ofl_action_push)); - if (sscanf(str, "0x%"SCNx16"", &(a->ethertype)) != 1) { - ofp_fatal(0, "Error parsing ethertype in push_mpls/vlan action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_POP_VLAN): { - struct ofl_action_header *a = xmalloc(sizeof(struct ofl_action_header)); - (*act) = a; - break; - } - case (OFPAT_POP_MPLS): { - struct ofl_action_pop_mpls *a = xmalloc(sizeof(struct ofl_action_pop_mpls)); - if (sscanf(str, "0x%"SCNx16"", &(a->ethertype)) != 1) { - ofp_fatal(0, "Error parsing ethertype in pop_mpls action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_SET_QUEUE): { - struct ofl_action_set_queue *a = xmalloc(sizeof(struct ofl_action_set_queue)); - if (parse32(str, NULL, 0, 0xffffffff, &(a->queue_id))) { - ofp_fatal(0, "Error parsing queue in queue action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_GROUP): { - struct ofl_action_group *a = xmalloc(sizeof(struct ofl_action_group)); - if (parse_group(str, &(a->group_id))) { - ofp_fatal(0, "Error parsing group in group action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_SET_NW_TTL): { - struct ofl_action_set_nw_ttl *a = xmalloc(sizeof(struct ofl_action_set_nw_ttl)); - if (parse8(str, NULL, 0, 255, &(a->nw_ttl))) { - ofp_fatal(0, "Error parsing ttl in mpls_ttl action: %s.", str); - } - (*act) = (struct ofl_action_header *)a; - break; - } - case (OFPAT_DEC_NW_TTL): { - struct ofl_action_header *a = xmalloc(sizeof(struct ofl_action_header)); - (*act) = a; - break; - } - default: { - ofp_fatal(0, "Error parsing action: %s.", str); - } - } - (*act)->type = type; -} - -static void -parse_actions(char *str, size_t *acts_num, struct ofl_action_header ***acts) { - char *token, *saveptr = NULL; - char *s; - size_t i; - bool found; - struct ofl_action_header *act = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - found = false; - for (i=0; iheader.type = OFPIT_GOTO_TABLE; - if (parse_table(s, &(i->table_id))) { - ofp_fatal(0, "Error parsing table in goto instruction: %s.", s); - } - (*inst) = (struct ofl_instruction_header *)i; - return; - } - case (OFPIT_WRITE_METADATA): { - char *token, *saveptr = NULL; - struct ofl_instruction_write_metadata *i = xmalloc(sizeof(struct ofl_instruction_write_metadata)); - i->header.type = OFPIT_WRITE_METADATA; - token = strtok_r(s, KEY_SEP, &saveptr); - if (sscanf(token, "0x%"SCNx64"", &(i->metadata)) != 1) { - ofp_fatal(0, "Error parsing metadata in write metadata instruction: %s.", s); - } - token = strtok_r(NULL, KEY_SEP, &saveptr); - if (token == NULL) { - i->metadata_mask = 0xffffffffffffffffULL; - } else { - if (sscanf(token, "0x%"SCNx64"", &(i->metadata_mask)) != 1) { - ofp_fatal(0, "Error parsing metadata_mask in write metadata instruction: %s.", s); - } - } - (*inst) = (struct ofl_instruction_header *)i; - return; - } - case (OFPIT_WRITE_ACTIONS): { - struct ofl_instruction_actions *i = xmalloc(sizeof(struct ofl_instruction_actions)); - i->header.type = OFPIT_WRITE_ACTIONS; - i->actions = NULL; - i->actions_num = 0; - parse_actions(s, &(i->actions_num), &(i->actions)); - (*inst) = (struct ofl_instruction_header *)i; - return; - } - case (OFPIT_APPLY_ACTIONS): { - struct ofl_instruction_actions *i = xmalloc(sizeof(struct ofl_instruction_actions)); - i->header.type = OFPIT_APPLY_ACTIONS; - i->actions = NULL; - i->actions_num = 0; - parse_actions(s, &(i->actions_num), &(i->actions)); - (*inst) = (struct ofl_instruction_header *)i; - return; - } - case (OFPIT_CLEAR_ACTIONS): { - struct ofl_instruction_header *i = xmalloc(sizeof(struct ofl_instruction_header)); - i->type = OFPIT_CLEAR_ACTIONS; - (*inst) = (struct ofl_instruction_header *)i; - return; - } - } - } - } - ofp_fatal(0, "Error parsing instruction: %s.", str); -} - - -static void -parse_flow_stat_args(char *str, struct ofl_msg_stats_request_flow *req) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, FLOW_MOD_COOKIE KEY_VAL, strlen(FLOW_MOD_COOKIE KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { - ofp_fatal(0, "Error parsing flow_stat cookie: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_COOKIE_MASK KEY_VAL, strlen(FLOW_MOD_COOKIE_MASK KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { - ofp_fatal(0, "Error parsing flow_stat cookie mask: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_TABLE_ID KEY_VAL, strlen(FLOW_MOD_TABLE_ID KEY_VAL)) == 0) { - if (parse8(token + strlen(FLOW_MOD_TABLE_ID KEY_VAL), table_names, NUM_ELEMS(table_names), 254, &req->table_id)) { - ofp_fatal(0, "Error parsing flow_stat table: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_OUT_PORT KEY_VAL, strlen(FLOW_MOD_OUT_PORT KEY_VAL)) == 0) { - if (parse_port(token + strlen(FLOW_MOD_OUT_PORT KEY_VAL), &req->out_port)) { - ofp_fatal(0, "Error parsing flow_stat port: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_OUT_GROUP KEY_VAL, strlen(FLOW_MOD_OUT_GROUP KEY_VAL)) == 0) { - if (parse_group(token + strlen(FLOW_MOD_OUT_GROUP KEY_VAL), &req->out_port)) { - ofp_fatal(0, "Error parsing flow_stat group: %s.", token); - } - continue; - } - ofp_fatal(0, "Error parsing flow_stat arg: %s.", token); - } -} - - - -static void -parse_flow_mod_args(char *str, struct ofl_msg_flow_mod *req) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, FLOW_MOD_COMMAND KEY_VAL, strlen(FLOW_MOD_COMMAND KEY_VAL)) == 0) { - uint8_t command; - if (parse8(token + strlen(FLOW_MOD_COMMAND KEY_VAL), flow_mod_cmd_names, NUM_ELEMS(flow_mod_cmd_names),0, &command)) { - ofp_fatal(0, "Error parsing flow_mod command: %s.", token); - } - req->command = command; - continue; - } - if (strncmp(token, FLOW_MOD_COOKIE KEY_VAL, strlen(FLOW_MOD_COOKIE KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { - ofp_fatal(0, "Error parsing flow_mod cookie: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_COOKIE_MASK KEY_VAL, strlen(FLOW_MOD_COOKIE_MASK KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_COOKIE KEY_VAL "0x%"SCNx64"", &(req->cookie)) != 1) { - ofp_fatal(0, "Error parsing flow_mod cookie mask: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_TABLE_ID KEY_VAL, strlen(FLOW_MOD_TABLE_ID KEY_VAL)) == 0) { - if (parse8(token + strlen(FLOW_MOD_TABLE_ID KEY_VAL), table_names, NUM_ELEMS(table_names), 254, &req->table_id)) { - ofp_fatal(0, "Error parsing flow_mod table: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_IDLE KEY_VAL, strlen(FLOW_MOD_IDLE KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_IDLE KEY_VAL "%"SCNu16"", &(req->idle_timeout)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", FLOW_MOD_IDLE, token); - } - continue; - } - if (strncmp(token, FLOW_MOD_HARD KEY_VAL, strlen(FLOW_MOD_HARD KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_HARD KEY_VAL "%"SCNu16"", &(req->hard_timeout)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", FLOW_MOD_HARD, token); - } - continue; - } - if (strncmp(token, FLOW_MOD_PRIO KEY_VAL, strlen(FLOW_MOD_PRIO KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_PRIO KEY_VAL "%"SCNu16"", &(req->priority)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", FLOW_MOD_PRIO, token); - } - continue; - } - if (strncmp(token, FLOW_MOD_BUFFER KEY_VAL, strlen(FLOW_MOD_BUFFER KEY_VAL)) == 0) { - if (parse32(token + strlen(FLOW_MOD_BUFFER KEY_VAL), buffer_names, NUM_ELEMS(buffer_names), UINT32_MAX, &req->buffer_id)) { - ofp_fatal(0, "Error parsing flow_mod buffer: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_OUT_PORT KEY_VAL, strlen(FLOW_MOD_OUT_PORT KEY_VAL)) == 0) { - if (parse_port(token + strlen(FLOW_MOD_OUT_PORT KEY_VAL), &req->out_port)) { - ofp_fatal(0, "Error parsing flow_mod port: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_OUT_GROUP KEY_VAL, strlen(FLOW_MOD_OUT_GROUP KEY_VAL)) == 0) { - if (parse_group(token + strlen(FLOW_MOD_OUT_GROUP KEY_VAL), &req->out_port)) { - ofp_fatal(0, "Error parsing flow_mod group: %s.", token); - } - continue; - } - if (strncmp(token, FLOW_MOD_FLAGS KEY_VAL, strlen(FLOW_MOD_FLAGS KEY_VAL)) == 0) { - if (sscanf(token, FLOW_MOD_FLAGS KEY_VAL "0x%"SCNx16"", &(req->flags)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", FLOW_MOD_FLAGS, token); - } - continue; - } - ofp_fatal(0, "Error parsing flow_mod arg: %s.", token); - } -} - -static void -parse_group_mod_args(char *str, struct ofl_msg_group_mod *req) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, GROUP_MOD_COMMAND KEY_VAL, strlen(GROUP_MOD_COMMAND KEY_VAL)) == 0) { - uint16_t command; - if (parse16(token + strlen(GROUP_MOD_COMMAND KEY_VAL), group_mod_cmd_names, NUM_ELEMS(group_mod_cmd_names),0, &command)) { - ofp_fatal(0, "Error parsing group_mod command: %s.", token); - } - req->command = command; - continue; - } - if (strncmp(token, GROUP_MOD_GROUP KEY_VAL, strlen(GROUP_MOD_GROUP KEY_VAL)) == 0) { - if (parse_group(token + strlen(GROUP_MOD_GROUP KEY_VAL), &req->group_id)) { - ofp_fatal(0, "Error parsing group_mod group: %s.", token); - } - continue; - } - if (strncmp(token, GROUP_MOD_TYPE KEY_VAL, strlen(GROUP_MOD_TYPE KEY_VAL)) == 0) { - uint8_t type; - if (parse8(token + strlen(GROUP_MOD_TYPE KEY_VAL), group_type_names, NUM_ELEMS(group_type_names), UINT8_MAX, &type)) { - ofp_fatal(0, "Error parsing group_mod type: %s.", token); - } - req->type = type; - continue; - } - ofp_fatal(0, "Error parsing group_mod arg: %s.", token); - } -} - -static void -parse_bucket(char *str, struct ofl_bucket *b) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, BUCKET_WEIGHT KEY_VAL, strlen(BUCKET_WEIGHT KEY_VAL)) == 0) { - if (parse16(token + strlen(BUCKET_WEIGHT KEY_VAL), NULL, 0, UINT16_MAX, &b->weight)) { - ofp_fatal(0, "Error parsing bucket_weight: %s.", token); - } - continue; - } - if (strncmp(token, BUCKET_WATCH_PORT KEY_VAL, strlen(BUCKET_WATCH_PORT KEY_VAL)) == 0) { - if (parse_port(token + strlen(BUCKET_WATCH_PORT KEY_VAL), &b->watch_port)) { - ofp_fatal(0, "Error parsing bucket watch port: %s.", token); - } - continue; - } - if (strncmp(token, BUCKET_WATCH_GROUP KEY_VAL, strlen(BUCKET_WATCH_GROUP KEY_VAL)) == 0) { - if (parse_group(token + strlen(BUCKET_WATCH_GROUP KEY_VAL), &b->watch_group)) { - ofp_fatal(0, "Error parsing bucket watch group: %s.", token); - } - continue; - } - ofp_fatal(0, "Error parsing bucket arg: %s.", token); - } -} - -static void -parse_config(char *str, struct ofl_config *c) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, CONFIG_FLAGS KEY_VAL, strlen(CONFIG_FLAGS KEY_VAL)) == 0) { - if (sscanf(token + strlen(CONFIG_FLAGS KEY_VAL), "0x%"SCNx16"", &c->flags) != 1) { - ofp_fatal(0, "Error parsing config flags: %s.", token); - } - continue; - } - if (strncmp(token, CONFIG_MISS KEY_VAL, strlen(CONFIG_MISS KEY_VAL)) == 0) { - if (parse16(token + strlen(CONFIG_MISS KEY_VAL), NULL, 0, UINT16_MAX - sizeof(struct ofp_packet_in), &c->miss_send_len)) { - ofp_fatal(0, "Error parsing config miss send len: %s.", token); - } - continue; - } - ofp_fatal(0, "Error parsing config arg: %s.", token); - } -} - -static void -parse_port_mod(char *str, struct ofl_msg_port_mod *msg) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, PORT_MOD_PORT KEY_VAL, strlen(PORT_MOD_PORT KEY_VAL)) == 0) { - if (parse_port(token + strlen(PORT_MOD_PORT KEY_VAL), &msg->port_no)) { - ofp_fatal(0, "Error parsing port_mod port: %s.", token); - } - continue; - } - if (strncmp(token, PORT_MOD_HW_ADDR KEY_VAL, strlen(PORT_MOD_HW_ADDR KEY_VAL)) == 0) { - if (parse_dl_addr(token + strlen(PORT_MOD_HW_ADDR KEY_VAL), msg->hw_addr)) { - ofp_fatal(0, "Error parsing port_mod hw_addr: %s.", token); - } - continue; - } - if (strncmp(token, PORT_MOD_HW_CONFIG KEY_VAL, strlen(PORT_MOD_HW_CONFIG KEY_VAL)) == 0) { - if (sscanf(token + strlen(PORT_MOD_HW_CONFIG KEY_VAL), "0x%"SCNx32"", &msg->config) != 1) { - ofp_fatal(0, "Error parsing port_mod conf: %s.", token); - } - continue; - } - if (strncmp(token, PORT_MOD_MASK KEY_VAL, strlen(PORT_MOD_MASK KEY_VAL)) == 0) { - if (sscanf(token + strlen(PORT_MOD_MASK KEY_VAL), "0x%"SCNx32"", &msg->mask) != 1) { - ofp_fatal(0, "Error parsing port_mod mask: %s.", token); - } - continue; - } - if (strncmp(token, PORT_MOD_ADVERTISE KEY_VAL, strlen(PORT_MOD_ADVERTISE KEY_VAL)) == 0) { - if (sscanf(token + strlen(PORT_MOD_ADVERTISE KEY_VAL), "0x%"SCNx32"", &msg->advertise) != 1) { - ofp_fatal(0, "Error parsing port_mod advertise: %s.", token); - } - continue; - } - ofp_fatal(0, "Error parsing port_mod arg: %s.", token); - } -} - - -static void -parse_table_mod(char *str, struct ofl_msg_table_mod *msg) { - char *token, *saveptr = NULL; - - for (token = strtok_r(str, KEY_SEP, &saveptr); token != NULL; token = strtok_r(NULL, KEY_SEP, &saveptr)) { - if (strncmp(token, TABLE_MOD_TABLE KEY_VAL, strlen(TABLE_MOD_TABLE KEY_VAL)) == 0) { - if (parse_table(token + strlen(TABLE_MOD_TABLE KEY_VAL), &msg->table_id)) { - ofp_fatal(0, "Error parsing table_mod table: %s.", token); - } - continue; - } - if (strncmp(token, TABLE_MOD_CONFIG KEY_VAL, strlen(TABLE_MOD_CONFIG KEY_VAL)) == 0) { - if (sscanf(token + strlen(TABLE_MOD_CONFIG KEY_VAL), "0x%"SCNx32"", &msg->config) != 1) { - ofp_fatal(0, "Error parsing table_mod conf: %s.", token); - } - continue; - } - ofp_fatal(0, "Error parsing table_mod arg: %s.", token); - } -} - - -static int -parse_port(char *str, uint32_t *port) { - return parse32(str, port_names, NUM_ELEMS(port_names), OFPP_MAX, port); -} - -static int -parse_queue(char *str, uint32_t *port) { - return parse32(str, queue_names, NUM_ELEMS(queue_names), 0xfffffffe, port); -} - -static int -parse_group(char *str, uint32_t *group) { - return parse32(str, group_names, NUM_ELEMS(group_names), OFPG_MAX, group); -} - -static int -parse_table(char *str, uint8_t *table) { - return parse8(str, table_names, NUM_ELEMS(table_names), 0xfe, table); -} - -static int -parse_dl_addr(char *str, uint8_t *addr) { - return (sscanf(str, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8, - addr, addr+1, addr+2, addr+3, addr+4, addr+5) != 6); -} - -static int -parse_nw_addr(char *str, uint32_t *addr) { - // TODO Zoltan: netmask ? - // TODO Zoltan: DNS lookup ? - uint8_t a[4]; - - if (sscanf(str, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8, - &a[0], &a[1], &a[2], &a[3]) == 4) { - *addr = (a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]; - return 0; - } - return -1; -} - -static int -parse_vlan_vid(char *str, uint16_t *vid) { - return parse16(str, vlan_vid_names, NUM_ELEMS(vlan_vid_names), 0xfff, vid); -} - - - - - -static int -parse8(char *str, struct names8 *names, size_t names_num, uint8_t max, uint8_t *val) { - size_t i; - - for (i=0; i 0) && (sscanf(str, "%"SCNu8"", val)) == 1 && (*val <= max)) { - return 0; - } - return -1; -} - -static int -parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val) { - size_t i; - - for (i=0; i 0) && (sscanf(str, "%"SCNx16"", val)) == 1 && (*val <= max)) { - return 0; - } - } - else { - if ((max > 0) && (sscanf(str, "%"SCNu16"", val)) == 1 && (*val <= max)) { - return 0; - } - } - return -1; -} - -static int -parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val) { - size_t i; - - for (i=0; i 0) && (sscanf(str, "%"SCNu32"", val)) == 1 && ((*val) <= max)) { - return 0; - } - return -1; -} - From 242bc555f95c345169cac4a8667a1aaca05fe77c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 8 Dec 2014 16:54:11 -0200 Subject: [PATCH 094/191] Various bug fixes. - Add checksum recalculation after set icmo fields. - Fix IPv6 flow label parsing - Fix incorrect size of VLAN pcp in the parsing - Correct netpdl specification for the IPv6 Neighbor Discovery source link layer field. --- customnetpdl.xml | 11 ++++--- nbee_link/nbee_link.cpp | 73 +++++++++++++++++++---------------------- udatapath/dp_actions.c | 31 ++++++++++------- 3 files changed, 60 insertions(+), 55 deletions(-) diff --git a/customnetpdl.xml b/customnetpdl.xml index 1cb226e6..c642fdec 100644 --- a/customnetpdl.xml +++ b/customnetpdl.xml @@ -892,9 +892,12 @@ - - - + + + + + + @@ -1412,7 +1415,7 @@ --> - + diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index 2693f3bb..237912dd 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -111,15 +111,6 @@ extern "C" int nblink_initialize(void) } -int nblink_add_entry_hmap(struct ofpbuf * pktin, struct hmap * pktout ,struct ofl_match_tlv * pktout_field, int Size) -/* -* This will add a field entry to the hash map structure. -*/ -{ - - - return 0; -} int nblink_check_for_entry_on_hmap(struct hmap * pktout ,uint32_t header, struct ofl_match_tlv * field) /* @@ -227,8 +218,7 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str * Function used to extract a field from the NetBee field structure. */ { -/* Found a NetPDL field usable on matching */ - +/* Found a NetPDL field usable on matching */ /* Copying data from the packet */ if (field->Mask != NULL) { @@ -241,10 +231,10 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str ofl_structs_match_put16(pktout, header, m_value); } else if (header == OXM_OF_VLAN_PCP){ - uint16_t m_value; - sscanf(field->Value, "%hx", &m_value); + uint8_t m_value; + sscanf(field->Value, "%hhx", &m_value); m_value = (m_value & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT; - ofl_structs_match_put16(pktout, header, m_value); + ofl_structs_match_put8(pktout, header, m_value); } else if(header == OXM_OF_IP_DSCP){ uint8_t m_value; @@ -282,14 +272,12 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str m_value = (m_value & PBB_ISID_MASK); ofl_structs_match_put32(pktout, header, m_value); } - /*TODO: Add IPV6_FLABEL_SHIFT to lib/packets.h*/ - /*else if (header == OXM_OF_IPV6_FLABEL){ + else if (header == OXM_OF_IPV6_FLABEL){ uint32_t m_value; sscanf(field->Value, "%x", &m_value); - m_value = (m_value & IPV6_FLABEL_MASK) >> IPV6_FLABEL_SHIFT; - memcpy(pktout_field->value, &m_value, field->Size); - - }*/ + m_value = m_value & IPV6_FLABEL_MASK; + ofl_structs_match_put32(pktout, header, m_value); + } } else { @@ -321,7 +309,6 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str } case 4:{ uint32_t m_value; - if (header == OXM_OF_IPV4_DST || header == OXM_OF_IPV4_SRC || header == OXM_OF_ARP_SPA || header == OXM_OF_ARP_TPA){ m_value = *((uint32_t*)((uint8_t*)pktin->data + field->Position)); @@ -394,7 +381,6 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk string field_Name (field->Name); /* Copying data from the packet */ - if (protocol_Name.compare("ethernet") == 0 && pkt_proto->eth == NULL) { pkt_proto->eth = (struct eth_header *) ( (uint8_t*) pktin->data + proto->Position); @@ -405,7 +391,7 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk PDMLReader->GetPDMLField(proto->Name, (char*) "type", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ETH_TYPE); - } + } else if ((protocol_Name.compare("vlan") == 0)) { if(pkt_proto->vlan_last == NULL){ @@ -473,14 +459,16 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk } else if (protocol_Name.compare("ipv6") == 0 && pkt_proto->ipv6 == NULL) { + _nbPDMLField * ip_proto = NULL; + uint8_t i; pkt_proto->ipv6 = (struct ipv6_header *) ((uint8_t*) pktin->data + proto->Position); PDMLReader->GetPDMLField(proto->Name, (char*) "flabel", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_FLABEL); /*Initialize extension header OXM */ struct ofl_match_tlv * EH_field; uint16_t bit_field = OFPIEH_NONEXT; - uint8_t i; EH_field = (struct ofl_match_tlv *) malloc(sizeof(struct ofl_match_tlv)); EH_field->value = (uint8_t*) malloc(OXM_LENGTH(OXM_OF_IPV6_EXTHDR)); EH_field->header = OXM_OF_IPV6_EXTHDR; @@ -502,16 +490,16 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk hmap_insert_fast(&pktout->match_fields, &EH_field->hmap_node, hash_int(EH_field->header, 0)); pktout->header.length += 6; + PDMLReader->GetPDMLField(proto->Name, (char*) "src", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_SRC); PDMLReader->GetPDMLField(proto->Name, (char*) "dst", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_DST); - PDMLReader->GetPDMLField(proto->Name, (char*) "nexthdr", proto->FirstField, &ip_proto); + PDMLReader->GetPDMLField(proto->Name, (char*) "nexthdr", proto->FirstField, &ip_proto); if (PDMLReader->GetPDMLField(proto->Name, (char*) "HBH", proto->FirstField, &field) == nbSUCCESS){ - nblink_extract_exthdr_fields(pktin, pktout, OFPIEH_HOP, field, &destination_num); - if(!field->NextField) + nblink_extract_exthdr_fields(pktin, pktout, OFPIEH_HOP, field, &destination_num); ip_proto = field->FirstChild; } if(PDMLReader->GetPDMLField(proto->Name, (char*) "FH", proto->FirstField, &field) == nbSUCCESS){ @@ -538,10 +526,11 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk nblink_extract_exthdr_fields(pktin, pktout, OFPIEH_ESP, field, &destination_num); if(!field->NextField) ip_proto = field->FirstChild; - } + } if (ip_proto){ + nblink_extract_proto_fields(pktin, ip_proto, pktout, OXM_OF_IP_PROTO); - } + } } if (protocol_Name.compare("tcp") == 0 && pkt_proto->tcp == NULL) { @@ -566,29 +555,34 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk if (protocol_Name.compare("icmp") == 0 && pkt_proto->icmp == NULL){ pkt_proto->icmp = (struct icmp_header *) ((uint8_t*) pktin->data + proto->Position); - PDMLReader->GetPDMLField(proto->Name, (char*) "type", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV4_TYPE); PDMLReader->GetPDMLField(proto->Name, (char*) "code", proto->FirstField, &field); - nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV4_CODE); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV4_CODE); + } else if (protocol_Name.compare("icmp6") == 0 && pkt_proto->icmp == NULL){ pkt_proto->icmp = (struct icmp_header *) ((uint8_t*) pktin->data + proto->Position); PDMLReader->GetPDMLField(proto->Name, (char*) "type", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV6_TYPE); - PDMLReader->GetPDMLField(proto->Name, (char*) "code", proto->FirstField, &field); + PDMLReader->GetPDMLField(proto->Name, (char*) "code", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV6_CODE); if (PDMLReader->GetPDMLField(proto->Name, (char*) "NeighSol", proto->FirstField, &field) == nbSUCCESS || PDMLReader->GetPDMLField(proto->Name, (char*) "NeighAdv", proto->FirstField, &field) == nbSUCCESS){ - PDMLReader->GetPDMLField(proto->Name, (char*) "target_address", proto->FirstField, &field); - nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_TARGET); + + PDMLReader->GetPDMLField(proto->Name, (char*) "target_address", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_TARGET); } if (PDMLReader->GetPDMLField(proto->Name, (char*) "NDO", proto->FirstField, &field) == nbSUCCESS){ - PDMLReader->GetPDMLField(proto->Name, (char*) "src link_layer_address", proto->FirstField, &field); - nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_SLL); - PDMLReader->GetPDMLField(proto->Name, (char*) "dst link_layer_address", proto->FirstField, &field); - nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_TLL); + uint8_t type; + PDMLReader->GetPDMLField(proto->Name, (char*) "ndotype", proto->FirstField, &field); + if (PDMLReader->GetPDMLField(proto->Name, (char*) "src_link_layer_address", proto->FirstField, &field) == nbSUCCESS){ + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_SLL); + } + if(PDMLReader->GetPDMLField(proto->Name, (char*) "dst_link_layer_address", proto->FirstField, &field) == nbSUCCESS){ + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_TLL); + } } } while (!field->isField) @@ -605,8 +599,7 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk } proto = proto->NextProto; - } - + } return 1; } diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 3bd39043..edf0fa8a 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -158,7 +158,6 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) uint16_t new_val, old_val; uint8_t proto = *act->field->value; old_val = htons((ipv4->ip_ttl << 8) + ipv4->ip_proto); - VLOG_ERR(LOG_MODULE, "Proto %d %d", ipv4->ip_proto, proto); new_val = htons((ipv4->ip_ttl << 8) + proto); ipv4->ip_csum = recalc_csum16(ipv4->ip_csum, old_val, new_val); ipv4->ip_proto = proto; @@ -209,7 +208,6 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) uint16_t v = htons(*(uint16_t*) act->field->value); tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src, v); memcpy(&tcp->tcp_src, &v, OXM_LENGTH(act->field->header)); - break; } case OXM_OF_TCP_DST:{ @@ -217,7 +215,6 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) uint16_t v = htons(*(uint16_t*) act->field->value); tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst, v); memcpy(&tcp->tcp_dst, &v, OXM_LENGTH(act->field->header)); - break; } case OXM_OF_UDP_SRC:{ @@ -238,28 +235,39 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) } /*TODO recalculate SCTP checksum*/ case OXM_OF_SCTP_SRC:{ - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - memcpy(&pkt->handle_std->proto->sctp->sctp_src, - v, OXM_LENGTH(act->field->header)); - break; + struct sctp_header *sctp = pkt->handle_std->proto->sctp; + uint16_t v = htons(*(uint16_t*) act->field->value); + /*TODO correct checksum */ + memcpy(&sctp->sctp_src, &v, OXM_LENGTH(act->field->header)); } case OXM_OF_SCTP_DST:{ uint16_t *v = (uint16_t*) act->field->value; *v = htons(*v); + /*TODO correct checksum */ memcpy(&pkt->handle_std->proto->sctp->sctp_dst, v, OXM_LENGTH(act->field->header)); break; } case OXM_OF_ICMPV4_TYPE: case OXM_OF_ICMPV6_TYPE:{ - pkt->handle_std->proto->icmp->icmp_type = *act->field->value; + struct icmp_header *icmp_header = pkt->handle_std->proto->icmp; + uint16_t new_val, old_val; + uint8_t icmp_type = *act->field->value; + old_val = htons((icmp_header->icmp_type << 8) + icmp_header->icmp_code); + new_val = htons((icmp_type << 8) + icmp_header->icmp_code); + icmp_header->icmp_csum = recalc_csum16(icmp_header->icmp_csum , old_val, new_val); + icmp_header->icmp_type = *act->field->value; break; } - case OXM_OF_ICMPV4_CODE: case OXM_OF_ICMPV6_CODE:{ - pkt->handle_std->proto->icmp->icmp_code = *act->field->value; + struct icmp_header *icmp_header = pkt->handle_std->proto->icmp; + uint16_t new_val, old_val; + uint8_t icmp_code = *act->field->value; + old_val = htons((icmp_header->icmp_type << 8) + icmp_header->icmp_code); + new_val = htons((icmp_header->icmp_type << 8) + icmp_code); + icmp_header->icmp_csum = recalc_csum16(icmp_header->icmp_csum , old_val, new_val); + icmp_header->icmp_code = *act->field->value; break; } case OXM_OF_ARP_OP: { @@ -289,6 +297,7 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) case OXM_OF_IPV6_SRC:{ memcpy(&pkt->handle_std->proto->ipv6->ipv6_src, act->field->value, OXM_LENGTH(act->field->header)); + break; } case OXM_OF_IPV6_DST:{ From 4e8c72d1d5e64c39dc50a0634144f7696e4d18b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 8 Dec 2014 17:07:31 -0200 Subject: [PATCH 095/191] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 77b918e9..cc7246be 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,10 @@ The following components are available in this package: # Getting Started -These instructions have been tested on Ubuntu 12.04. Other distributions or versions may need different steps. +These instructions have been tested on Ubuntu 12.04. Other distributions or versions may need different steps. + +For Ubuntu 14.04, please check @castroflavio solution: +[How to compile on Ubuntu 14.04][compileubuntu14] ## Before building The switch makes use of the NetBee library to parse packets, so we need to install it first. @@ -155,3 +158,4 @@ E-mail: Eder Leao Fernandes (ederleaofernandes at gmail . com) [ofp13]: https://www.opennetworking.org/images/stories/downloads/specification/openflow-spec-v1.3.0.pdf [ericssonsw11]: https://github.com/TrafficLab/of11softswitch +[compileubuntu14]: http://tocai.dia.uniroma3.it/compunet-wiki/index.php/Installing_and_setting_up_OpenFlow_tools From 70e1eb02b7745ca2c5ec79d132fc5e60fdfaddfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Tue, 9 Dec 2014 22:49:32 -0200 Subject: [PATCH 096/191] Correct IPv6 ecn and dscp parsing IPv6 ecn and dscp fields were missing on the packet parsing engine. --- customnetpdl.xml | 4 ++-- lib/packets.h | 2 +- nbee_link/nbee_link.cpp | 35 +++++++++++++++++++++++++++-------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/customnetpdl.xml b/customnetpdl.xml index c642fdec..ff1e02d0 100644 --- a/customnetpdl.xml +++ b/customnetpdl.xml @@ -893,8 +893,8 @@ - - + + diff --git a/lib/packets.h b/lib/packets.h index c4ca42e8..c8189052 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -261,7 +261,7 @@ BUILD_ASSERT_DECL(IP_HEADER_LEN == sizeof(struct ip_header)); #define IPV6_VERSION 6 #define IPV6_DSCP_MASK 0x0fc00000 #define IPV6_DSCP_SHIFT 22 -#define IPV6_ECN_MASK 0x00300000 +#define IPV6_ECN_MASK 0x0003 #define IPV6_ECN_SHIFT 20 #define IPV6_FLABEL_MASK 0x000fffff #define IPV6_HEADER_LEN 40 diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index 237912dd..d6ccb834 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -238,15 +238,31 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str } else if(header == OXM_OF_IP_DSCP){ uint8_t m_value; - sscanf(field->Value, "%hhx", &m_value); - m_value = (m_value & IP_DSCP_MASK) >> 2; - ofl_structs_match_put8(pktout, header, m_value); + if (strcmp(field->Name, "ip dscp") == 0){ + sscanf(field->Value, "%hhx", &m_value); + m_value = (m_value & IP_DSCP_MASK) >> 2; + ofl_structs_match_put8(pktout, header, m_value); + } + else { + uint32_t field_value; + sscanf(field->Value, "%x", &field_value); + m_value = (field_value & IPV6_DSCP_MASK) >> IPV6_DSCP_SHIFT; + ofl_structs_match_put8(pktout, header, m_value); + } } else if(header == OXM_OF_IP_ECN){ uint8_t m_value; - sscanf(field->Value, "%hhx", &m_value); - m_value = m_value & IP_ECN_MASK; - ofl_structs_match_put8(pktout, header, m_value); + if (strcmp(field->Name, "ip ecn") == 0){ + sscanf(field->Value, "%hhx", &m_value); + m_value = (m_value & IP_ECN_MASK) >> IPV6_ECN_SHIFT; + ofl_structs_match_put8(pktout, header, m_value); + } + else { + uint32_t field_value; + sscanf(field->Value, "%x", &field_value); + m_value = field_value & IPV6_ECN_MASK; + ofl_structs_match_put8(pktout, header, m_value); + } } else if(header == OXM_OF_MPLS_LABEL){ uint32_t m_value; @@ -463,8 +479,11 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk _nbPDMLField * ip_proto = NULL; uint8_t i; pkt_proto->ipv6 = (struct ipv6_header *) ((uint8_t*) pktin->data + proto->Position); - PDMLReader->GetPDMLField(proto->Name, (char*) "flabel", proto->FirstField, &field); - + PDMLReader->GetPDMLField(proto->Name, (char*) "ipv6 dscp", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IP_DSCP); + PDMLReader->GetPDMLField(proto->Name, (char*) "ipv6 ecn", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IP_ECN); + PDMLReader->GetPDMLField(proto->Name, (char*) "flabel", proto->FirstField, &field); nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_FLABEL); /*Initialize extension header OXM */ struct ofl_match_tlv * EH_field; From 01baa960fdda19a1bf8701f508a501d1cf133f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Tue, 9 Dec 2014 23:38:55 -0200 Subject: [PATCH 097/191] Add tcp and udp checksum recalculation after ipv6 src and dst set_field. The addition fix wrong checksum error after a set_field action with ipv6 src or ipv6 dst. --- lib/csum.c | 27 +++++++++++++++++++++++++++ lib/csum.h | 2 ++ udatapath/dp_actions.c | 24 +++++++++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/lib/csum.c b/lib/csum.c index 81b3dc13..430e7bac 100644 --- a/lib/csum.c +++ b/lib/csum.c @@ -113,3 +113,30 @@ recalc_csum32(uint16_t old_csum, uint32_t old_u32, uint32_t new_u32) return recalc_csum16(recalc_csum16(old_csum, old_u32, new_u32), old_u32 >> 16, new_u32 >> 16); } + +/* Returns the new checksum for a packet in which the checksum field previously + * contained 'old_csum' and in which a field that contained 'old_u64' was + * changed to contain 'new_u64'. */ +uint16_t +recalc_csum64(uint16_t old_csum, uint64_t old_u64, uint64_t new_u64) +{ + return recalc_csum32(recalc_csum32(old_csum, old_u64, new_u64), + old_u64 >> 32, new_u64 >> 32); +} + + +/* Returns the new checksum for a packet in which the checksum field previously + * contained 'old_csum' and in which a field that contained 'old_u32' was + * changed to contain 'new_u12'. */ +uint16_t +recalc_csum128(uint16_t old_csum, uint8_t old_u128[16], uint8_t new_u128[16]) +{ + uint64_t old_left, old_right; + uint64_t new_left, new_right; + old_right = *((uint64_t*) ( old_u128 + 8 )); + new_right = *((uint64_t*) ( new_u128 + 8 )); + old_left = *((uint64_t*) ( old_u128 )); + new_left = *((uint64_t*) ( new_u128 )); + return recalc_csum64(recalc_csum64(old_csum, old_right, new_right), + old_left, new_left); +} \ No newline at end of file diff --git a/lib/csum.h b/lib/csum.h index d9253e00..50ecb898 100644 --- a/lib/csum.h +++ b/lib/csum.h @@ -44,5 +44,7 @@ uint32_t csum_continue(uint32_t partial, const void *, size_t); uint16_t csum_finish(uint32_t partial); uint16_t recalc_csum16(uint16_t old_csum, uint16_t old_u16, uint16_t new_u16); uint16_t recalc_csum32(uint16_t old_csum, uint32_t old_u32, uint32_t new_u32); +uint16_t recalc_csum64(uint16_t old_csum, uint64_t old_u64, uint64_t new_u64); +uint16_t recalc_csum128(uint16_t old_csum, uint8_t old_u128[16], uint8_t new_u128[16]); #endif /* csum.h */ diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index edf0fa8a..173e3a69 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -295,14 +295,36 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) break; } case OXM_OF_IPV6_SRC:{ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + /*Reconstruct TCP or UDP checksum*/ + if (pkt->handle_std->proto->tcp != NULL) { + struct tcp_header *tcp = pkt->handle_std->proto->tcp; + tcp->tcp_csum = recalc_csum128(tcp->tcp_csum, + ipv6->ipv6_src.s6_addr, act->field->value); + } else if (pkt->handle_std->proto->udp != NULL) { + struct udp_header *udp = pkt->handle_std->proto->udp; + udp->udp_csum = recalc_csum128(udp->udp_csum, + ipv6->ipv6_src.s6_addr, act->field->value); + } memcpy(&pkt->handle_std->proto->ipv6->ipv6_src, act->field->value, OXM_LENGTH(act->field->header)); - break; } case OXM_OF_IPV6_DST:{ + struct ipv6_header *ipv6 = pkt->handle_std->proto->ipv6; + /*Reconstruct TCP or UDP checksum*/ + if (pkt->handle_std->proto->tcp != NULL) { + struct tcp_header *tcp = pkt->handle_std->proto->tcp; + tcp->tcp_csum = recalc_csum128(tcp->tcp_csum, + ipv6->ipv6_dst.s6_addr, act->field->value); + } else if (pkt->handle_std->proto->udp != NULL) { + struct udp_header *udp = pkt->handle_std->proto->udp; + udp->udp_csum = recalc_csum128(udp->udp_csum, + ipv6->ipv6_dst.s6_addr, act->field->value); + } memcpy(&pkt->handle_std->proto->ipv6->ipv6_dst, act->field->value, OXM_LENGTH(act->field->header)); + break; } case OXM_OF_IPV6_FLABEL:{ From 31ccda60d55341947b7b48f48939a30b9a6e8923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Wed, 10 Dec 2014 00:04:10 -0200 Subject: [PATCH 098/191] Add support to match sctp This commmit introduces to the parsing engine the specification of the sctp header. Now it is possible to match sctp src and dst ports. --- customnetpdl.xml | 26 ++++++++++++++++++++++++-- lib/packets.h | 2 +- nbee_link/nbee_link.cpp | 4 ++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/customnetpdl.xml b/customnetpdl.xml index ff1e02d0..091ed67b 100644 --- a/customnetpdl.xml +++ b/customnetpdl.xml @@ -737,6 +737,7 @@ + @@ -1043,7 +1044,7 @@ - + @@ -1737,7 +1738,6 @@ -
@@ -1749,6 +1749,28 @@ + + + + + + + + + + + + + +
+ + + + + + + + diff --git a/lib/packets.h b/lib/packets.h index c8189052..3ffd6270 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -349,7 +349,7 @@ BUILD_ASSERT_DECL(TCP_HEADER_LEN == sizeof(struct tcp_header)); struct sctp_header { uint16_t sctp_src; uint16_t sctp_dst; - uint32_t sctp_verif; + uint32_t sctp_ver_tag; uint32_t sctp_csum; }; BUILD_ASSERT_DECL(SCTP_HEADER_LEN == sizeof(struct sctp_header)); diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index d6ccb834..ef6cdfa9 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -570,6 +570,10 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk else if (protocol_Name.compare("sctp") == 0 && pkt_proto->sctp == NULL) { pkt_proto->sctp = (struct sctp_header *) ((uint8_t*) pktin->data + proto->Position); + PDMLReader->GetPDMLField(proto->Name, (char*) "sport", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_SCTP_SRC); + PDMLReader->GetPDMLField(proto->Name, (char*) "dport", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_SCTP_DST); } if (protocol_Name.compare("icmp") == 0 && pkt_proto->icmp == NULL){ From 7b2d263570a79b3f6c566e4950fd9fce8ee7cd57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 11 Dec 2014 18:25:09 -0200 Subject: [PATCH 099/191] Recalculate sctp check sum after set_field action. This commit fixes wrong checksum of sctp packets after changes due to a set_field action on the field sctp src and dst ports. Also changes the crc32.c and crc32.h files with code to calculate the crc32c, used by the sctp checksum. --- udatapath/crc32.c | 177 ++++++++++++++++++++++++++++------------- udatapath/crc32.h | 130 ++++++++++++++++++++---------- udatapath/dp_actions.c | 30 ++++--- 3 files changed, 227 insertions(+), 110 deletions(-) diff --git a/udatapath/crc32.c b/udatapath/crc32.c index f6c2c0b3..f1503569 100644 --- a/udatapath/crc32.c +++ b/udatapath/crc32.c @@ -1,68 +1,131 @@ -/* 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. - */ +/** + * \file crc32c.c + * Functions and types for CRC checks. + * + * Generated on Thu Dec 11 18:04:34 2014, + * by pycrc v0.8.2, http://www.tty1.net/pycrc/ + * using the configuration: + * Width = 32 + * Poly = 0x1edc6f41 + * XorIn = 0xffffffff + * ReflectIn = True + * XorOut = 0xffffffff + * ReflectOut = True + * Algorithm = table-driven + *****************************************************************************/ +#include "crc32.h" /* include the header file generated with pycrc */ +#include +#include -#include -#include "crc32.h" +/** + * Static table used for the table_driven implementation. + *****************************************************************************/ +static const crc_t crc_table[256] = { + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, + 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, + 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, + 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, + 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, + 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, + 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, + 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, + 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, + 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, + 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, + 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, + 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, + 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, + 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, + 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, + 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, + 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, + 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, + 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, + 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, + 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, + 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, + 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, + 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, + 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, + 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, + 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, + 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, + 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, + 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, + 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, + 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351 +}; -void -crc32_init(struct crc32 *crc, unsigned int polynomial) +/** + * Reflect all bits of a \a data word of \a data_len bytes. + * + * \param data The data word to be reflected. + * \param data_len The width of \a data expressed in number of bits. + * \return The reflected data. + *****************************************************************************/ +crc_t crc_reflect(crc_t data, size_t data_len) { - int i; + unsigned int i; + crc_t ret; - 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; + ret = data & 0x01; + for (i = 1; i < data_len; i++) { + data >>= 1; + ret = (ret << 1) | (data & 0x01); } + return ret; } -unsigned int -crc32_calculate(const struct crc32 *crc, const void *data_, size_t n_bytes) + +/** + * Update the crc value with new data. + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param data_len Number of bytes in the \a data buffer. + * \return The updated crc value. + *****************************************************************************/ +crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len) { - const uint8_t *data = data_; - unsigned int result = 0; - size_t i; + unsigned int tbl_idx; + + while (data_len--) { + tbl_idx = (crc ^ *data) & 0xff; + crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff; - for (i = 0; i < n_bytes; i++) { - unsigned int top = result >> 24; - top ^= data[i]; - result = (result << 8) ^ crc->table[top]; + data++; } - return result; + return crc & 0xffffffff; } + diff --git a/udatapath/crc32.h b/udatapath/crc32.h index 355aefdf..4421ee98 100644 --- a/udatapath/crc32.h +++ b/udatapath/crc32.h @@ -1,50 +1,92 @@ -/* 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 +/** + * \file crc32c.h + * Functions and types for CRC checks. + * + * Generated on Thu Dec 11 18:04:29 2014, + * by pycrc v0.8.2, http://www.tty1.net/pycrc/ + * using the configuration: + * Width = 32 + * Poly = 0x1edc6f41 + * XorIn = 0xffffffff + * ReflectIn = True + * XorOut = 0xffffffff + * ReflectOut = True + * Algorithm = table-driven + *****************************************************************************/ +#ifndef __CRC32C_H__ +#define __CRC32C_H__ +#include #include -#include -#define CRC32_TABLE_BITS 8 -#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS) +#ifdef __cplusplus +extern "C" { +#endif -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); +/** + * The definition of the used algorithm. + * + * This is not used anywhere in the generated code, but it may be used by the + * application code to call algoritm-specific code, is desired. + *****************************************************************************/ +#define CRC_ALGO_TABLE_DRIVEN 1 -#endif /* crc32.h */ + +/** + * The type of the CRC values. + * + * This type must be big enough to contain at least 32 bits. + *****************************************************************************/ +typedef uint_fast32_t crc_t; + + +/** + * Reflect all bits of a \a data word of \a data_len bytes. + * + * \param data The data word to be reflected. + * \param data_len The width of \a data expressed in number of bits. + * \return The reflected data. + *****************************************************************************/ +crc_t crc_reflect(crc_t data, size_t data_len); + + +/** + * Calculate the initial crc value. + * + * \return The initial crc value. + *****************************************************************************/ +static inline crc_t crc_init(void) +{ + return 0xffffffff; +} + + +/** + * Update the crc value with new data. + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param data_len Number of bytes in the \a data buffer. + * \return The updated crc value. + *****************************************************************************/ +crc_t crc_update(crc_t crc, const unsigned char *data, size_t data_len); + + +/** + * Calculate the final crc value. + * + * \param crc The current crc value. + * \return The final crc value. + *****************************************************************************/ +static inline crc_t crc_finalize(crc_t crc) +{ + return crc ^ 0xffffffff; +} + + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif + +#endif /* __CRC32C_H__ */ \ No newline at end of file diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 173e3a69..7fbd5b67 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -43,6 +43,7 @@ #include "packet.h" #include "packets.h" #include "pipeline.h" +#include "crc32.h" #include "util.h" #include "oflib/oxm-match.h" #include "hash.h" @@ -230,23 +231,34 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) uint16_t v = htons(*(uint16_t*) act->field->value); udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, v); memcpy(&udp->udp_dst, &v, OXM_LENGTH(act->field->header)); - break; } /*TODO recalculate SCTP checksum*/ case OXM_OF_SCTP_SRC:{ - struct sctp_header *sctp = pkt->handle_std->proto->sctp; + crc_t crc; + struct sctp_header *sctp = pkt->handle_std->proto->sctp; + size_t len = ((uint8_t*) ofpbuf_tail(pkt->handle_std->pkt->buffer)) - (uint8_t *) sctp; uint16_t v = htons(*(uint16_t*) act->field->value); - /*TODO correct checksum */ + sctp->sctp_csum = 0; memcpy(&sctp->sctp_src, &v, OXM_LENGTH(act->field->header)); + crc = crc_init(); + crc = crc_update(crc, (unsigned char*)sctp, len); + crc = crc_finalize(crc); + sctp->sctp_csum = crc; + break; } case OXM_OF_SCTP_DST:{ - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - /*TODO correct checksum */ - memcpy(&pkt->handle_std->proto->sctp->sctp_dst, - v, OXM_LENGTH(act->field->header)); - break; + crc_t crc; + struct sctp_header *sctp = pkt->handle_std->proto->sctp; + size_t len = ((uint8_t*) ofpbuf_tail(pkt->handle_std->pkt->buffer)) - (uint8_t *) sctp; + uint16_t v = htons(*(uint16_t*) act->field->value); + sctp->sctp_csum = 0; + memcpy(&sctp->sctp_dst, &v, OXM_LENGTH(act->field->header)); + crc = crc_init(); + crc = crc_update(crc, (unsigned char*)sctp, len); + crc = crc_finalize(crc); + sctp->sctp_csum = crc; + break; } case OXM_OF_ICMPV4_TYPE: case OXM_OF_ICMPV6_TYPE:{ From 80ceb15b70fc7eeedb25380a2815c7b69bdb6b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Sat, 13 Dec 2014 00:17:27 -0200 Subject: [PATCH 100/191] Fix IPv6 neighbor discovery target pre requisites check. The check for icmp type was not working because of the order of insertion on the flow mod message parsing. Also it fixes the set_field action, calculating the checksum after change the neighbor discovery target field. This commit also removes unecessary debugging printf. --- oflib/oxm-match.c | 37 +++++++++++++++++++++++-------------- udatapath/dp_actions.c | 6 +++++- udatapath/match_std.c | 1 - 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/oflib/oxm-match.c b/oflib/oxm-match.c index cdf2f6e1..6d01a415 100644 --- a/oflib/oxm-match.c +++ b/oflib/oxm-match.c @@ -219,13 +219,13 @@ oxm_prereqs_ok(const struct oxm_field *field, const struct ofl_match *rule) { struct ofl_match_tlv *omt = NULL; - + bool found = false; /*Check ICMP type*/ if (field->header == OXM_OF_IPV6_ND_SLL || field->header == OXM_OF_IPV6_ND_TARGET ){ - bool found = false; + HMAP_FOR_EACH_WITH_HASH (omt, struct ofl_match_tlv, hmap_node, hash_int(OXM_OF_ICMPV6_TYPE, 0), &rule->match_fields) { - if (*omt->value != ICMPV6_NEIGHSOL){ + if (*(omt)->value != ICMPV6_NEIGHSOL){ return false; } found = true; @@ -234,8 +234,7 @@ oxm_prereqs_ok(const struct oxm_field *field, const struct ofl_match *rule) return false; } /*Check ICMP type*/ - if (field->header == OXM_OF_IPV6_ND_TLL || field->header == OXM_OF_IPV6_ND_TARGET){ - bool found = false; + if ((field->header == OXM_OF_IPV6_ND_TLL || field->header == OXM_OF_IPV6_ND_TARGET) && !found){ HMAP_FOR_EACH_WITH_HASH (omt, struct ofl_match_tlv, hmap_node, hash_int(OXM_OF_ICMPV6_TYPE, 0), &rule->match_fields) { if (*omt->value != ICMPV6_NEIGHADV){ @@ -249,7 +248,7 @@ oxm_prereqs_ok(const struct oxm_field *field, const struct ofl_match *rule) /*Check for IP_PROTO */ if (field->nw_proto){ - bool found = false; + found = false; HMAP_FOR_EACH_WITH_HASH (omt, struct ofl_match_tlv, hmap_node, hash_int(OXM_OF_IP_PROTO, 0), &rule->match_fields) { uint8_t ip_proto; @@ -471,23 +470,25 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, case OFI_OXM_OF_UDP_DST: /* SCTP header. */ case OFI_OXM_OF_SCTP_SRC: - case OFI_OXM_OF_SCTP_DST: - ofl_structs_match_put16(match, f->header, ntohs(*((uint16_t*) value))); - return 0; + case OFI_OXM_OF_SCTP_DST:{ + ofl_structs_match_put16(match, f->header, ntohs(*((uint16_t*) value))); + return 0; + } /* ICMP header. */ case OFI_OXM_OF_ICMPV4_TYPE: case OFI_OXM_OF_ICMPV4_CODE: /* ICMPv6 header. */ case OFI_OXM_OF_ICMPV6_TYPE: case OFI_OXM_OF_ICMPV6_CODE:{ - uint8_t *v = (uint8_t*) value; - ofl_structs_match_put8(match, f->header, *v); + uint8_t *v = (uint8_t*) value; + ofl_structs_match_put8(match, f->header, *v); return 0; } /* IPv6 Neighbor Discovery. */ - case OFI_OXM_OF_IPV6_ND_TARGET: - ofl_structs_match_put_ipv6(match, f->header,(uint8_t* ) value); + case OFI_OXM_OF_IPV6_ND_TARGET:{ + ofl_structs_match_put_ipv6(match, f->header,(uint8_t* ) value); return 0; + } case OFI_OXM_OF_IPV6_ND_SLL: case OFI_OXM_OF_IPV6_ND_TLL: ofl_structs_match_put_eth(match, f->header,(uint8_t* )value); @@ -776,7 +777,8 @@ oxm_put_eth_dst(struct ofpbuf *b, static bool is_requisite(uint32_t header){ if(header == OXM_OF_IN_PORT || header == OXM_OF_ETH_TYPE - || header == OXM_OF_VLAN_VID || header == OXM_OF_IP_PROTO) { + || header == OXM_OF_VLAN_VID || header == OXM_OF_IP_PROTO || + header == OXM_OF_ICMPV6_TYPE) { return true; } return false; @@ -825,6 +827,13 @@ int oxm_put_match(struct ofpbuf *buf, struct ofl_match *omt){ oxm_put_8(buf,oft->header, value); } + HMAP_FOR_EACH_WITH_HASH(oft, struct ofl_match_tlv, hmap_node, hash_int(OXM_OF_ICMPV6_TYPE, 0), + &omt->match_fields) { + uint8_t value; + memcpy(&value, oft->value,sizeof(uint8_t)); + oxm_put_8(buf,oft->header, value); + } + /* Loop through the remaining fields */ HMAP_FOR_EACH(oft, struct ofl_match_tlv, hmap_node, &omt->match_fields){ diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 7fbd5b67..8ebea0f2 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -351,12 +351,16 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) case OXM_OF_IPV6_ND_TARGET:{ struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; + uint8_t * old_value; uint8_t *data = (uint8_t*)icmp; /*ICMP header + neighbor discovery header reserverd bytes*/ offset = sizeof(struct icmp_header) + 4; - + old_value = data + offset; memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); + + icmp->icmp_csum = recalc_csum128(icmp->icmp_csum, + old_value, act->field->value); break; } case OXM_OF_IPV6_ND_SLL: diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 201ddaaa..284ce6df 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -105,7 +105,6 @@ static inline bool match_64(uint8_t *a, uint8_t *b) { uint64_t *a1 = (uint64_t *) a; uint64_t *b1 = (uint64_t *) b; - VLOG_ERR(LOG_MODULE, "Result %"PRIx64" %"PRIx64"", *a1, *b1); return (*a1 == *b1); } From 0fe63d4ca90f83c6279efcdbcf826743427719d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Sun, 14 Dec 2014 22:25:25 -0200 Subject: [PATCH 101/191] Fix wrong checksum calculation of IPv6 neighbor discovery target. --- udatapath/dp_actions.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 8ebea0f2..5de35a04 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -351,16 +351,15 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) case OXM_OF_IPV6_ND_TARGET:{ struct icmp_header *icmp = pkt->handle_std->proto->icmp; uint8_t offset; - uint8_t * old_value; + uint8_t old_value[16]; uint8_t *data = (uint8_t*)icmp; - /*ICMP header + neighbor discovery header reserverd bytes*/ + /*ICMP header + neighbor discovery header reserved bytes*/ offset = sizeof(struct icmp_header) + 4; - old_value = data + offset; + memcpy(old_value, data + offset, OXM_LENGTH(act->field->header)); memcpy(data + offset, act->field->value, OXM_LENGTH(act->field->header)); - icmp->icmp_csum = recalc_csum128(icmp->icmp_csum, - old_value, act->field->value); + old_value, act->field->value); break; } case OXM_OF_IPV6_ND_SLL: From f92e60862cad6904a5634081f3ec416c9b5f0461 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Mon, 15 Dec 2014 17:39:49 -0200 Subject: [PATCH 102/191] Fix multipart duration nsec field. This commit fix a bug when computing duration_nsec field from stats multipart messages. This field must carry the duration in nanoseconds beyond duration_sec, but it was computing the value value in microseconds. --- udatapath/dp_ports.c | 4 ++-- udatapath/flow_entry.c | 2 +- udatapath/group_entry.c | 2 +- udatapath/meter_entry.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/udatapath/dp_ports.c b/udatapath/dp_ports.c index 9609f9f8..6122607d 100644 --- a/udatapath/dp_ports.c +++ b/udatapath/dp_ports.c @@ -704,7 +704,7 @@ dp_ports_handle_port_mod(struct datapath *dp, struct ofl_msg_port_mod *msg, static void dp_port_stats_update(struct sw_port *port) { port->stats->duration_sec = (time_msec() - port->created) / 1000; - port->stats->duration_nsec = ((time_msec() - port->created) % 1000) * 1000; + port->stats->duration_nsec = ((time_msec() - port->created) % 1000) * 1000000; } void @@ -796,7 +796,7 @@ dp_ports_handle_port_desc_request(struct datapath *dp, static void dp_ports_queue_update(struct sw_queue *queue) { queue->stats->duration_sec = (time_msec() - queue->created) / 1000; - queue->stats->duration_nsec = ((time_msec() - queue->created) % 1000) * 1000; + queue->stats->duration_nsec = ((time_msec() - queue->created) % 1000) * 1000000; } ofl_err diff --git a/udatapath/flow_entry.c b/udatapath/flow_entry.c index e361d982..06695a93 100644 --- a/udatapath/flow_entry.c +++ b/udatapath/flow_entry.c @@ -191,7 +191,7 @@ flow_entry_hard_timeout(struct flow_entry *entry) { void flow_entry_update(struct flow_entry *entry) { entry->stats->duration_sec = (time_msec() - entry->created) / 1000; - entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000; + entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000000; } /* Returns true if the flow entry has a reference to the given group. */ diff --git a/udatapath/group_entry.c b/udatapath/group_entry.c index e61774f8..b50c8166 100644 --- a/udatapath/group_entry.c +++ b/udatapath/group_entry.c @@ -317,7 +317,7 @@ group_entry_execute(struct group_entry *entry, void group_entry_update(struct group_entry *entry){ entry->stats->duration_sec = (time_msec() - entry->created) / 1000; - entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000; + entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000000; } /* Returns true if the group entry has reference to the flow entry. */ diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index 8a4db8d1..18fa626e 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -142,7 +142,7 @@ meter_entry_create(struct datapath *dp, struct meter_table *table, struct ofl_ms void meter_entry_update(struct meter_entry *entry) { entry->stats->duration_sec = (time_msec() - entry->created) / 1000; - entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000; + entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000000; } void From 9942fb14a6ca80977a570cff835ba1679286157c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Tue, 16 Dec 2014 23:31:04 -0200 Subject: [PATCH 103/191] Fix pbb_isid size to conform with the specification. This huge commit brings lots of changes to conform the the pbb isid match field size to conform with the OpenFlow 1.3.4 specification. Also, changes the code to reconstruct the vlan tag to check if the ethertype the default value for VLANs or is the one belonging to PBB. --- lib/netdev.c | 8 +- lib/ofp.c~ | 763 ------------------------------------- lib/ofp.h~ | 140 ------- lib/packets.h | 2 + nbee_link/nbee_link.cpp | 8 +- oflib/ofl-actions-pack.c | 2 +- oflib/ofl-actions-unpack.c | 2 +- oflib/ofl-packets.h | 1 + oflib/ofl-structs-match.c | 26 ++ oflib/ofl-structs-print.c | 4 +- oflib/ofl-structs.h | 6 + oflib/oxm-match.c | 50 ++- oflib/oxm-match.h | 4 +- udatapath/dp_actions.c | 7 +- udatapath/match_std.c | 58 ++- 15 files changed, 158 insertions(+), 923 deletions(-) delete mode 100644 lib/ofp.c~ delete mode 100644 lib/ofp.h~ diff --git a/lib/netdev.c b/lib/netdev.c index 76923f75..ae7fec51 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -1006,10 +1006,16 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) continue; /* VLAN tag found. Shift MAC addresses down and insert VLAN tag */ /* Create headroom for the VLAN tag */ + uint16_t* eth_type = (uint16_t *)(buffer->data + ETHER_ADDR_LEN * 2); ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN); memmove(buffer->data, (uint8_t*)buffer->data+VLAN_HEADER_LEN, ETH_ALEN * 2); tag = (struct vlan_tag *)((uint8_t*)buffer->data + ETH_ALEN * 2); - tag->vlan_tp_id = htons(ETH_P_8021Q); + if (ntohs(*eth_type) == ETH_TYPE_VLAN_PBB_S){ + tag->vlan_tp_id = htons(ETH_TYPE_VLAN_PBB_B); + } + else { + tag->vlan_tp_id = htons(ETH_P_8021Q); + } tag->vlan_tci = htons(aux->tp_vlan_tci); } #else diff --git a/lib/ofp.c~ b/lib/ofp.c~ deleted file mode 100644 index 3ebf083d..00000000 --- a/lib/ofp.c~ +++ /dev/null @@ -1,763 +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. - */ - -/* Zoltan: - * During the move to OpenFlow 1.1 parts of the code was taken from - * the following repository, with the license below: - * git://openflow.org/of1.1-spec-test.git (lib/ofp-util.h) - */ -/* - * Copyright (c) 2008, 2009, 2010 Nicira Networks. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include "ofp.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "openflow/nicira-ext.h" -#include "packets.h" -#include "random.h" -#include "util.h" - -#define LOG_MODULE VLM_ofp -#include "vlog.h" - -/* XXX we should really use consecutive xids to avoid probabilistic - * failures. */ -static inline uint32_t -alloc_xid(void) -{ - return random_uint32(); -} - -/* Allocates and stores in '*bufferp' a new ofpbuf with a size of - * 'openflow_len', starting with an OpenFlow header with the given 'type' and - * an arbitrary transaction id. Allocated bytes beyond the header, if any, are - * zeroed. - * - * The caller is responsible for freeing '*bufferp' when it is no longer - * needed. - * - * The OpenFlow header length is initially set to 'openflow_len'; if the - * message is later extended, the length should be updated with - * update_openflow_length() before sending. - * - * Returns the header. */ -void * -make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **bufferp) -{ - *bufferp = ofpbuf_new(openflow_len); - return put_openflow_xid(openflow_len, type, alloc_xid(), *bufferp); -} - -/* Allocates and stores in '*bufferp' a new ofpbuf with a size of - * 'openflow_len', starting with an OpenFlow header with the given 'type' and - * transaction id 'xid'. Allocated bytes beyond the header, if any, are - * zeroed. - * - * The caller is responsible for freeing '*bufferp' when it is no longer - * needed. - * - * The OpenFlow header length is initially set to 'openflow_len'; if the - * message is later extended, the length should be updated with - * update_openflow_length() before sending. - * - * Returns the header. */ -void * -make_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid, - struct ofpbuf **bufferp) -{ - *bufferp = ofpbuf_new(openflow_len); - return put_openflow_xid(openflow_len, type, xid, *bufferp); -} - -/* Appends 'openflow_len' bytes to 'buffer', starting with an OpenFlow header - * with the given 'type' and an arbitrary transaction id. Allocated bytes - * beyond the header, if any, are zeroed. - * - * The OpenFlow header length is initially set to 'openflow_len'; if the - * message is later extended, the length should be updated with - * update_openflow_length() before sending. - * - * Returns the header. */ -void * -put_openflow(size_t openflow_len, uint8_t type, struct ofpbuf *buffer) -{ - return put_openflow_xid(openflow_len, type, alloc_xid(), buffer); -} - -/* Appends 'openflow_len' bytes to 'buffer', starting with an OpenFlow header - * with the given 'type' and an transaction id 'xid'. Allocated bytes beyond - * the header, if any, are zeroed. - * - * The OpenFlow header length is initially set to 'openflow_len'; if the - * message is later extended, the length should be updated with - * update_openflow_length() before sending. - * - * Returns the header. */ -void * -put_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid, - struct ofpbuf *buffer) -{ - struct ofp_header *oh; - - assert(openflow_len >= sizeof *oh); - assert(openflow_len <= UINT16_MAX); - - oh = ofpbuf_put_uninit(buffer, openflow_len); - oh->version = OFP_VERSION; - oh->type = type; - oh->length = htons(openflow_len); - oh->xid = xid; - memset(oh + 1, 0, openflow_len - sizeof *oh); - return oh; -} - -/* Updates the 'length' field of the OpenFlow message in 'buffer' to - * 'buffer->size'. */ -void -update_openflow_length(struct ofpbuf *buffer) -{ - struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); - oh->length = htons(buffer->size); -} - -/* Updates the 'len' field of the instruction header in 'buffer' to - * "what it should be"(tm). */ -void -update_instruction_length(struct ofpbuf *buffer, size_t oia_offset) -{ - struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh); - struct ofp_instruction *ih = ofpbuf_at_assert(buffer, oia_offset, - sizeof *ih); - ih->len = htons(buffer->size - oia_offset); -} - -struct ofpbuf * -make_flow_mod(uint8_t command, uint8_t table_id, - const struct flow *flow, size_t actions_len) -{ - struct ofp_flow_mod *ofm; - size_t size = sizeof *ofm + actions_len; - struct ofpbuf *out = ofpbuf_new(size); - ofm = ofpbuf_put_zeros(out, sizeof *ofm); - ofm->header.version = OFP_VERSION; - ofm->header.type = OFPT_FLOW_MOD; - ofm->header.length = htons(size); - ofm->cookie = 0; - /*TODO fill match - ofm->match.in_port = flow->in_port; - memcpy(ofm->match.dl_src, flow->dl_src, sizeof ofm->match.dl_src); - memcpy(ofm->match.dl_dst, flow->dl_dst, sizeof ofm->match.dl_dst); - ofm->match.dl_vlan = flow->dl_vlan; - ofm->match.dl_vlan_pcp = flow->dl_vlan_pcp; - ofm->match.dl_type = flow->dl_type; - ofm->match.nw_src = flow->nw_src; - ofm->match.nw_dst = flow->nw_dst; - ofm->match.nw_proto = flow->nw_proto; - ofm->match.nw_tos = flow->nw_tos; - ofm->match.tp_src = flow->tp_src; - ofm->match.tp_dst = flow->tp_dst; */ - ofm->command = command; - ofm->table_id = table_id; - - return out; -} - -struct ofpbuf * -make_add_flow(const struct flow *flow, uint32_t buffer_id, uint8_t table_id, - uint16_t idle_timeout, size_t actions_len) -{ - struct ofp_instruction_actions *oia; - size_t instruction_len = sizeof *oia + actions_len; - struct ofpbuf *out = make_flow_mod(OFPFC_ADD, table_id, - flow, instruction_len); - struct ofp_flow_mod *ofm = out->data; - ofm->idle_timeout = htons(idle_timeout); - ofm->hard_timeout = htons(OFP_FLOW_PERMANENT); - ofm->buffer_id = htonl(buffer_id); - /* Use a single apply-actions for now - Jean II */ - oia = ofpbuf_put_zeros(out, sizeof *oia); - oia->type = htons(OFPIT_APPLY_ACTIONS); - oia->len = htons(instruction_len); - return out; -} - - - -struct ofpbuf * -make_del_flow(const struct flow *flow, uint8_t table_id) -{ - struct ofpbuf *out = make_flow_mod(OFPFC_DELETE_STRICT, table_id, flow, 0); - struct ofp_flow_mod *ofm = out->data; - ofm->out_port = htonl(OFPP_ANY); - return out; -} - - -struct ofpbuf * -make_add_simple_flow(const struct flow *flow, - uint32_t buffer_id, uint32_t out_port, - uint16_t idle_timeout) -{ - if (out_port != OFPP_ANY) { - struct ofp_action_output *oao; - struct ofpbuf *buffer; - - buffer = make_add_flow(flow, buffer_id, 0x00, idle_timeout, sizeof *oao); - oao = ofpbuf_put_zeros(buffer, sizeof *oao); - oao->type = htons(OFPAT_OUTPUT); - oao->len = htons(sizeof *oao); - oao->port = htonl(out_port); - return buffer; - } else { - return make_add_flow(flow, buffer_id, 0, idle_timeout, 0); - } -} - - - -struct ofpbuf * -make_packet_out(const struct ofpbuf *packet, uint32_t buffer_id, - uint32_t in_port, - const struct ofp_action_header *actions, size_t n_actions) -{ - size_t actions_len = n_actions * sizeof *actions; - struct ofp_packet_out *opo; - size_t size = sizeof *opo + actions_len + (packet ? packet->size : 0); - struct ofpbuf *out = ofpbuf_new(size); - - opo = ofpbuf_put_uninit(out, sizeof *opo); - opo->header.version = OFP_VERSION; - opo->header.type = OFPT_PACKET_OUT; - opo->header.length = htons(size); - opo->header.xid = htonl(0); - opo->buffer_id = htonl(buffer_id); - opo->in_port = htonl(in_port); - opo->actions_len = htons(actions_len); - ofpbuf_put(out, actions, actions_len); - if (packet) { - ofpbuf_put(out, packet->data, packet->size); - } - return out; -} - - -struct ofpbuf * -make_unbuffered_packet_out(const struct ofpbuf *packet, - uint32_t in_port, uint32_t out_port) -{ - struct ofp_action_output action; - action.type = htons(OFPAT_OUTPUT); - action.len = htons(sizeof action); - action.port = htonl(out_port); - return make_packet_out(packet, UINT32_MAX, in_port, - (struct ofp_action_header *) &action, 1); -} - -struct ofpbuf * -make_buffered_packet_out(uint32_t buffer_id, - uint32_t in_port, uint32_t out_port) -{ - if (out_port != OFPP_ANY) { - struct ofp_action_output action; - action.type = htons(OFPAT_OUTPUT); - action.len = htons(sizeof action); - action.port = htonl(out_port); - return make_packet_out(NULL, buffer_id, in_port, - (struct ofp_action_header *) &action, 1); - } else { - return make_packet_out(NULL, buffer_id, in_port, NULL, 0); - } -} - - -/* Creates and returns an OFPT_ECHO_REQUEST message with an empty payload. */ -struct ofpbuf * -make_echo_request(void) -{ - struct ofp_header *rq; - struct ofpbuf *out = ofpbuf_new(sizeof *rq); - rq = ofpbuf_put_uninit(out, sizeof *rq); - rq->version = OFP_VERSION; - rq->type = OFPT_ECHO_REQUEST; - rq->length = htons(sizeof *rq); - rq->xid = alloc_xid(); - return out; -} - -/* Creates and returns an OFPT_ECHO_REPLY message matching the - * OFPT_ECHO_REQUEST message in 'rq'. */ -struct ofpbuf * -make_echo_reply(const struct ofp_header *rq) -{ - size_t size = ntohs(rq->length); - struct ofpbuf *out = ofpbuf_new(size); - struct ofp_header *reply = ofpbuf_put(out, rq, size); - reply->type = OFPT_ECHO_REPLY; - return out; -} - - -static int -check_message_type(uint8_t got_type, uint8_t want_type) -{ - if (got_type != want_type) { - VLOG_WARN(LOG_MODULE, "received bad message type %d (expected %d)", - got_type, want_type); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE);; - } - return 0; -} - -/* Checks that 'msg' has type 'type' and that it is exactly 'size' bytes long. - * Returns 0 if the checks pass, otherwise an OpenFlow error code (produced - * with ofp_mkerr()). */ -int -check_ofp_message(const struct ofp_header *msg, uint8_t type, size_t size) -{ - size_t got_size; - int error; - - error = check_message_type(msg->type, type); - if (error) { - return error; - } - - got_size = ntohs(msg->length); - if (got_size != size) { - VLOG_WARN(LOG_MODULE, "received %d message of length %zu (expected %zu)", - type, got_size, size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - - return 0; -} - -/* Checks that 'inst' has type 'type' and that 'inst' is 'size' plus a - * nonnegative integer multiple of 'array_elt_size' bytes long. Returns 0 if - * the checks pass, otherwise an OpenFlow error code (produced with - * ofp_mkerr()). - * - * If 'n_array_elts' is nonnull, then '*n_array_elts' is set to the number of - * 'array_elt_size' blocks in 'msg' past the first 'min_size' bytes, when - * successful. */ -int -check_ofp_instruction_array(const struct ofp_instruction *inst, uint8_t type, - size_t min_size, size_t array_elt_size, - size_t *n_array_elts) -{ - size_t got_size; - - assert(array_elt_size); - - if (ntohs(inst->type) != type) { - VLOG_WARN(LOG_MODULE, "received bad instruction type %X (expected %X)", - ntohs(inst->type), type); - return ofp_mkerr(OFPET_BAD_INSTRUCTION, OFPBIC_UNSUP_INST); - } - - got_size = ntohs(inst->len); - if (got_size < min_size) { - VLOG_WARN(LOG_MODULE, "received %X instruction of length %zu " - "(expected at least %zu)", - type, got_size, min_size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - if ((got_size - min_size) % array_elt_size) { - VLOG_WARN(LOG_MODULE, "received %X message of bad length %zu: the " - "excess over %zu (%zu) is not evenly divisible by %zu " - "(remainder is %zu)", - type, got_size, min_size, got_size - min_size, - array_elt_size, (got_size - min_size) % array_elt_size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);; - } - if (n_array_elts) { - *n_array_elts = (got_size - min_size) / array_elt_size; - } - return 0; -} - - -/* Checks that 'msg' has type 'type' and that 'msg' is 'size' plus a - * nonnegative integer multiple of 'array_elt_size' bytes long. Returns 0 if - * the checks pass, otherwise an OpenFlow error code (produced with - * ofp_mkerr()). - * - * If 'n_array_elts' is nonnull, then '*n_array_elts' is set to the number of - * 'array_elt_size' blocks in 'msg' past the first 'min_size' bytes, when - * successful. */ -int -check_ofp_message_array(const struct ofp_header *msg, uint8_t type, - size_t min_size, size_t array_elt_size, - size_t *n_array_elts) -{ - size_t got_size; - int error; - - assert(array_elt_size); - - error = check_message_type(msg->type, type); - if (error) { - return error; - } - - got_size = ntohs(msg->length); - if (got_size < min_size) { - VLOG_WARN(LOG_MODULE, "received %d message of length %zu " - "(expected at least %zu)", - type, got_size, min_size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - if ((got_size - min_size) % array_elt_size) { - VLOG_WARN(LOG_MODULE, - "received %d message of bad length %zu: the " - "excess over %zu (%zu) is not evenly divisible by %zu " - "(remainder is %zu)", - type, got_size, min_size, got_size - min_size, - array_elt_size, (got_size - min_size) % array_elt_size); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - if (n_array_elts) { - *n_array_elts = (got_size - min_size) / array_elt_size; - } - return 0; -} - - -int -check_ofp_packet_out(const struct ofp_header *oh, struct ofpbuf *data, - int *n_actionsp, int max_ports) -{ - const struct ofp_packet_out *opo; - unsigned int actions_len, n_actions; - size_t extra; - int error; - - *n_actionsp = 0; - error = check_ofp_message_array(oh, OFPT_PACKET_OUT, - sizeof *opo, 1, &extra); - if (error) { - return error; - } - opo = (const struct ofp_packet_out *) oh; - - actions_len = ntohs(opo->actions_len); - if (actions_len > extra) { - VLOG_WARN(LOG_MODULE, "packet-out claims %u bytes of actions " - "but message has room for only %zu bytes", - actions_len, extra); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - if (actions_len % sizeof(union ofp_action)) { - VLOG_WARN(LOG_MODULE, "packet-out claims %u bytes of actions, " - "which is not a multiple of %zu", - actions_len, sizeof(union ofp_action)); - return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } - - n_actions = actions_len / sizeof(union ofp_action); - error = validate_actions((const union ofp_action *) opo->actions, - n_actions, max_ports, true); - if (error) { - return error; - } - - data->data = (void *) &opo->actions[n_actions]; - data->size = extra - actions_len; - *n_actionsp = n_actions; - return 0; -} - -/*const struct ofp_flow_stats */ -const struct ofp_flow_stats * -flow_stats_first(struct flow_stats_iterator *iter, - const struct ofp_stats_reply *osr) -{ - iter->pos = osr->body; - iter->end = osr->body + (ntohs(osr->header.length) - - offsetof(struct ofp_stats_reply, body)); - return flow_stats_next(iter); -} - -/*const struct ofp_flow_stats */ -const struct ofp_flow_stats * -flow_stats_next(struct flow_stats_iterator *iter) -{ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - ptrdiff_t bytes_left = iter->end - iter->pos; - const struct ofp_flow_stats *fs; - size_t length; - - if (bytes_left < sizeof *fs) { - if (bytes_left != 0) { - VLOG_WARN_RL(LOG_MODULE, &rl, "%td leftover bytes in flow stats reply", - bytes_left); - } - return NULL; - } - - fs = (const void *) iter->pos; - length = ntohs(fs->length); - if (length < sizeof *fs) { - VLOG_WARN_RL(LOG_MODULE, &rl, "flow stats length %zu is shorter than min %zu", - length, sizeof *fs); - return NULL; - } else if (length > bytes_left) { - VLOG_WARN_RL(LOG_MODULE, &rl, "flow stats length %zu but only %td bytes left", - length, bytes_left); - return NULL; - } - /* TODO: Change instructions - else if ((length - sizeof *fs) % sizeof fs->instructions[0]) { - VLOG_WARN_RL(LOG_MODULE, &rl, "flow stats length %zu has %zu bytes " - "left over in final action", length, - (length - sizeof *fs) % sizeof fs->instructions[0]); - return NULL; - }*/ - iter->pos += length; - return fs; -} - -/* Alignment of ofp_actions. */ -#define ACTION_ALIGNMENT 8 - - -static int -check_action_exact_len(const union ofp_action *a, unsigned int len, - unsigned int required_len) -{ - if (len != required_len) { - VLOG_DBG(LOG_MODULE, "action %u has invalid length %"PRIu16" (must be %u)\n", - a->type, ntohs(a->header.len), required_len); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } - return 0; -} - -/* Checks that 'port' is a valid output port for the OFPAT_OUTPUT action, given - * that the switch will never have more than 'max_ports' ports. Returns 0 if - * 'port' is valid, otherwise an ofp_mkerr() return code.*/ -static int -check_output_port(uint32_t port, int max_ports, bool table_allowed) -{ - switch (port) { - case OFPP_IN_PORT: - case OFPP_NORMAL: - case OFPP_FLOOD: - case OFPP_ALL: - case OFPP_CONTROLLER: - case OFPP_LOCAL: - return 0; - - case OFPP_TABLE: - if (table_allowed) { - return 0; - } else { - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT); - } - - default: - if (port < max_ports) { - return 0; - } - VLOG_WARN(LOG_MODULE, "unknown output port %x", port); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT);; - } -} - -/* Checks that 'action' is a valid OFPAT_ENQUEUE action, given that the switch - * will never have more than 'max_ports' ports. Returns 0 if 'port' is valid, - * otherwise an ofp_mkerr() return code.*/ -static int -check_setqueue_action(const union ofp_action *a, unsigned int len) -{ - const struct ofp_action_set_queue *oaq; - int error; - - error = check_action_exact_len(a, len, 8); - if (error) { - return error; - } - - oaq = (const struct ofp_action_set_queue *) a; - return 0; -} - -static int -check_nicira_action(const union ofp_action *a, unsigned int len) -{ - const struct nx_action_header *nah; - - if (len < 16) { - VLOG_DBG(LOG_MODULE, "Nicira vendor action only %u bytes", len); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN);; - } - nah = (const struct nx_action_header *) a; - - switch (ntohs(nah->subtype)) { - case NXAST_RESUBMIT: - case NXAST_SET_TUNNEL: - return check_action_exact_len(a, len, 16); - default: - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_EXPERIMENTER); - } -} - -static int -check_action(const union ofp_action *a, unsigned int len, int max_ports, - bool is_packet_out) -{ - int error; - - switch (ntohs(a->type)) { - case OFPAT_OUTPUT: { - const struct ofp_action_output *oao; - error = check_action_exact_len(a, len, 16); - if (error) { - return error; - } - oao = (const struct ofp_action_output *) a; - return check_output_port(ntohl(oao->port), max_ports, is_packet_out); - } - - - case OFPAT_EXPERIMENTER: - return (a->experimenter.experimenter == htonl(NX_VENDOR_ID) - ? check_nicira_action(a, len) - : ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_EXPERIMENTER)); - - case OFPAT_SET_QUEUE: - return check_setqueue_action(a, len); - - default: - VLOG_WARN(LOG_MODULE, "unknown action type %"PRIu16, - ntohs(a->type)); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); - } -} - -int -validate_actions(const union ofp_action *actions, size_t n_actions, - int max_ports, bool is_packet_out) -{ - const union ofp_action *a; - - for (a = actions; a < &actions[n_actions]; ) { - unsigned int len = ntohs(a->header.len); - unsigned int n_slots = len / ACTION_ALIGNMENT; - unsigned int slots_left = &actions[n_actions] - a; - int error; - - if (n_slots > slots_left) { - VLOG_DBG(LOG_MODULE, - "action requires %u slots but only %u remain", - n_slots, slots_left); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } else if (!len) { - VLOG_DBG(LOG_MODULE, "action has invalid length 0"); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } else if (len % ACTION_ALIGNMENT) { - VLOG_DBG(LOG_MODULE, "action length %u is not a multiple " - "of %d", len, ACTION_ALIGNMENT); - return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); - } - - error = check_action(a, len, max_ports, is_packet_out); - if (error) { - return error; - } - a += n_slots; - } - return 0; -} - -/* Returns true if 'action' outputs to 'port' (which must be in network byte - * order), false otherwise. */ -bool -action_outputs_to_port(const union ofp_action *action, uint32_t port) -{ - switch (ntohs(action->type)) { - case OFPAT_OUTPUT: { - const struct ofp_action_output *oao; - oao = (const struct ofp_action_output *) action; - return oao->port == port; - } - default: - return false; - } -} - -/* The set of actions must either come from a trusted source or have been - * previously validated with validate_actions().*/ -const union ofp_action * -actions_first(struct actions_iterator *iter, - const union ofp_action *oa, size_t n_actions) -{ - iter->pos = oa; - iter->end = oa + n_actions; - return actions_next(iter); -} - -const union ofp_action * -actions_next(struct actions_iterator *iter) -{ - if (iter->pos < iter->end) { - const union ofp_action *a = iter->pos; - unsigned int len = ntohs(a->header.len); - iter->pos += len / ACTION_ALIGNMENT; - return a; - } else { - return NULL; - } -} - - - diff --git a/lib/ofp.h~ b/lib/ofp.h~ deleted file mode 100644 index eca9ab94..00000000 --- a/lib/ofp.h~ +++ /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. - */ - -/* Zoltan: - * During the move to OpenFlow 1.1 parts of the code was taken from - * the following repository, with the license below: - * git://openflow.org/of1.1-spec-test.git (lib/ofp-util.h) - */ -/* - * Copyright (c) 2008, 2009, 2010 Nicira Networks. - * - * 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. - */ - - -#ifndef OFP_H -#define OFP_H 1 - -#include -#include -#include -#include -#include "ofpbuf.h" -#include "flow.h" -#include "../include/openflow/openflow.h" - -/* OpenFlow protocol utility functions. */ -void *make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **); -void *make_openflow_xid(size_t openflow_len, uint8_t type, - uint32_t xid, struct ofpbuf **); -void *put_openflow(size_t openflow_len, uint8_t type, struct ofpbuf *); -void *put_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid, - struct ofpbuf *); -void update_openflow_length(struct ofpbuf *); -void update_instruction_length(struct ofpbuf *, size_t oia_offset); -struct ofpbuf *make_flow_mod(uint8_t command, uint8_t table_id, - const struct flow *, size_t actions_len); -struct ofpbuf *make_add_flow(const struct flow *, uint32_t buffer_id, - uint8_t table_id, - uint16_t max_idle, size_t actions_len); -struct ofpbuf *make_del_flow(const struct flow *, uint8_t table_id); -struct ofpbuf *make_add_simple_flow(const struct flow *, - uint32_t buffer_id, uint32_t out_port, - uint16_t max_idle); - -struct ofpbuf *make_packet_out(const struct ofpbuf *packet, uint32_t buffer_id, - uint32_t in_port, - const struct ofp_action_header *, - size_t n_actions); -struct ofpbuf *make_buffered_packet_out(uint32_t buffer_id, - uint32_t in_port, uint32_t out_port); -struct ofpbuf *make_unbuffered_packet_out(const struct ofpbuf *packet, - uint32_t in_port, uint32_t out_port); -struct ofpbuf *make_echo_request(void); -struct ofpbuf *make_echo_reply(const struct ofp_header *rq); -int check_ofp_message(const struct ofp_header *, uint8_t type, size_t size); -int check_ofp_instruction_array(const struct ofp_instruction *, uint8_t type, - size_t size, size_t array_elt_size, - size_t *n_array_elts); -int check_ofp_message_array(const struct ofp_header *, uint8_t type, - size_t size, size_t array_elt_size, - size_t *n_array_elts); -int check_ofp_packet_out(const struct ofp_header *, struct ofpbuf *data, - int *n_actions, int max_ports); - -struct flow_stats_iterator { - const uint8_t *pos, *end; -}; -const struct ofp_flow_stats *flow_stats_first(struct flow_stats_iterator *, - const struct ofp_stats_reply *); -const struct ofp_flow_stats *flow_stats_next(struct flow_stats_iterator *); - -struct actions_iterator { - const union ofp_action *pos, *end; -}; -const union ofp_action *actions_first(struct actions_iterator *, - const union ofp_action *, - size_t n_actions); -const union ofp_action *actions_next(struct actions_iterator *); -int validate_actions(const union ofp_action *, size_t n_actions, - int max_ports, bool is_packet_out); -bool action_outputs_to_port(const union ofp_action *, uint32_t port); - - -static inline int -ofp_mkerr(uint16_t type, uint16_t code) -{ - assert(type > 0 && type <= 0x7fff); - return (type << 16) | code; -} - -/* Hack to get the action parser to do sort of the right stuff. */ -union ofp_action { - uint16_t type; - struct ofp_action_header header; - struct ofp_action_experimenter_header experimenter; -}; -OFP_ASSERT(sizeof(union ofp_action) == 8); - -#endif /* ofp.h */ diff --git a/lib/packets.h b/lib/packets.h index 3ffd6270..c79528f5 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -381,6 +381,8 @@ struct qtag_prefix { uint16_t tci; }; + +#define PBB_ISID_LEN 3 #define PBB_HEADER_LEN 18 #define PBB_ISID_MASK 0xffffff diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index ef6cdfa9..04dc4416 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -284,9 +284,13 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str } else if (header == OXM_OF_PBB_ISID){ uint32_t m_value; + uint8_t pbb_isid[3]; sscanf(field->Value, "%x", &m_value); m_value = (m_value & PBB_ISID_MASK); - ofl_structs_match_put32(pktout, header, m_value); + pbb_isid[0] = (m_value >> 24) & 0xff; + pbb_isid[1] = (m_value >> 16) & 0xff; + pbb_isid[2] = m_value & 0xff; + ofl_structs_match_put_pbb_isid(pktout, header, pbb_isid); } else if (header == OXM_OF_IPV6_FLABEL){ uint32_t m_value; @@ -593,8 +597,8 @@ extern "C" int nblink_packet_parse(struct ofpbuf * pktin, struct ofl_match * pk nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_ICMPV6_CODE); if (PDMLReader->GetPDMLField(proto->Name, (char*) "NeighSol", proto->FirstField, &field) == nbSUCCESS || PDMLReader->GetPDMLField(proto->Name, (char*) "NeighAdv", proto->FirstField, &field) == nbSUCCESS){ - PDMLReader->GetPDMLField(proto->Name, (char*) "target_address", proto->FirstField, &field); + nblink_extract_proto_fields(pktin, field, pktout, OXM_OF_IPV6_ND_TARGET); } if (PDMLReader->GetPDMLField(proto->Name, (char*) "NDO", proto->FirstField, &field) == nbSUCCESS){ diff --git a/oflib/ofl-actions-pack.c b/oflib/ofl-actions-pack.c index dbdecc29..1c35f04e 100644 --- a/oflib/ofl-actions-pack.c +++ b/oflib/ofl-actions-pack.c @@ -207,10 +207,10 @@ ofl_actions_pack(struct ofl_action_header *src, struct ofp_action_header *dst, u switch (OXM_LENGTH(sa->field->header)){ case 1: case 6: + case 3: case 16: memcpy(data + (sizeof(struct ofp_action_set_field)), sa->field->value, OXM_LENGTH(sa->field->header)); break; - case 2:{ uint16_t value = htons(*((uint16_t*) sa->field->value)); memcpy(data + (sizeof(struct ofp_action_set_field)),&value,OXM_LENGTH(sa->field->header)); diff --git a/oflib/ofl-actions-unpack.c b/oflib/ofl-actions-unpack.c index 7e24191a..6954b29e 100644 --- a/oflib/ofl-actions-unpack.c +++ b/oflib/ofl-actions-unpack.c @@ -292,11 +292,11 @@ ofl_actions_unpack(struct ofp_action_header *src, size_t *len, struct ofl_action } switch(OXM_LENGTH(da->field->header)){ case 1: + case 3: case 6: case 16: memcpy(da->field->value , value, OXM_LENGTH(da->field->header)); break; - case 2:{ uint16_t v = ntohs(*((uint16_t*) value)); memcpy(da->field->value , &v, OXM_LENGTH(da->field->header)); diff --git a/oflib/ofl-packets.h b/oflib/ofl-packets.h index 2b3eb067..78893163 100644 --- a/oflib/ofl-packets.h +++ b/oflib/ofl-packets.h @@ -40,6 +40,7 @@ #define ETH_TYPE_MPLS 0x8847 #define ETH_TYPE_MPLS_MCAST 0x8848 +#define PBB_ISID_LEN 3 #define ETH_ADDR_LEN 6 #define IPv6_ADDR_LEN 16 diff --git a/oflib/ofl-structs-match.c b/oflib/ofl-structs-match.c index 8147611a..61fd4ca6 100644 --- a/oflib/ofl-structs-match.c +++ b/oflib/ofl-structs-match.c @@ -147,6 +147,32 @@ ofl_structs_match_put64m(struct ofl_match *match, uint32_t header, uint64_t valu } +void +ofl_structs_match_put_pbb_isid(struct ofl_match *match, uint32_t header, uint8_t value[PBB_ISID_LEN]){ + struct ofl_match_tlv *m = malloc(sizeof (struct ofl_match_tlv)); + int len = OXM_LENGTH(header); + + m->header = header; + m->value = malloc(len); + memcpy(m->value, value, len); + hmap_insert(&match->match_fields,&m->hmap_node,hash_int(header, 0)); + match->header.length += len + 4; +} + + +void +ofl_structs_match_put_pbb_isidm(struct ofl_match *match, uint32_t header, uint8_t value[PBB_ISID_LEN], uint8_t mask[PBB_ISID_LEN]){ + struct ofl_match_tlv *m = malloc(sizeof (struct ofl_match_tlv)); + int len = OXM_LENGTH(header); + + m->header = header; + m->value = malloc(len*2); + memcpy(m->value, value, len); + memcpy(m->value + len, mask, len); + hmap_insert(&match->match_fields,&m->hmap_node,hash_int(header, 0)); + match->header.length += len*2 + 4; +} + void ofl_structs_match_put_eth(struct ofl_match *match, uint32_t header, uint8_t value[ETH_ADDR_LEN]){ struct ofl_match_tlv *m = malloc(sizeof (struct ofl_match_tlv)); diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index 62683ecc..2cba7059 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -404,9 +404,9 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) } break; case OFPXMT_OFB_PBB_ISID : - fprintf(stream, "pbb_isid=\"%d\"", *((uint32_t*) f->value)); + fprintf(stream, "pbb_isid=\"%x%x%x\"", f->value[0],f->value[1], f->value[2]); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", pbb_isid_mask=\"%d\"", *((uint32_t*)(f->value+4))); + fprintf(stream, ", pbb_isid_mask=\"%x%x%x\"", (f->value+4)[0], (f->value+4)[1], (f->value+4)[2]); } break; case OFPXMT_OFB_TUNNEL_ID: diff --git a/oflib/ofl-structs.h b/oflib/ofl-structs.h index 5c4dde64..ca2f867e 100644 --- a/oflib/ofl-structs.h +++ b/oflib/ofl-structs.h @@ -432,6 +432,12 @@ ofl_structs_match_put64(struct ofl_match *match, uint32_t header, uint64_t value void ofl_structs_match_put64m(struct ofl_match *match, uint32_t header, uint64_t value, uint64_t mask); +void +ofl_structs_match_put_pbb_isid(struct ofl_match *match, uint32_t header, uint8_t value[PBB_ISID_LEN]); + +void +ofl_structs_match_put_pbb_isidm(struct ofl_match *match, uint32_t header, uint8_t value[PBB_ISID_LEN], uint8_t mask[PBB_ISID_LEN]); + void ofl_structs_match_put_eth(struct ofl_match *match, uint32_t header, uint8_t value[ETH_ADDR_LEN]); diff --git a/oflib/oxm-match.c b/oflib/oxm-match.c index 6d01a415..9282474a 100644 --- a/oflib/oxm-match.c +++ b/oflib/oxm-match.c @@ -95,7 +95,7 @@ oxm_init(void) int i; for (i = 0; i < NUM_OXM_FIELDS; i++) { - struct oxm_field *f = &all_fields[i]; + struct oxm_field *f = &all_fields[i]; hmap_insert(&all_oxm_fields, &f->hmap_node, hash_int(f->header, 0)); } @@ -173,7 +173,6 @@ struct oxm_field * oxm_field_lookup(uint32_t header) { struct oxm_field *f; - oxm_init(); HMAP_FOR_EACH_WITH_HASH(f, struct oxm_field, hmap_node, hash_int(header, 0), @@ -512,14 +511,20 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, return 0; } case OFI_OXM_OF_PBB_ISID:{ - ofl_structs_match_put32(match, f->header, ntohl(*((uint32_t*) value))); - return 0; + uint8_t* pbb_isid; + pbb_isid = value; + ofl_structs_match_put_pbb_isid(match, f->header, pbb_isid); + return 0; } case OFI_OXM_OF_PBB_ISID_W:{ + uint8_t* pbb_isid; + uint8_t* pbb_isid_mask; + pbb_isid = value; + pbb_isid_mask = mask; if (check_bad_wildcard32(*((uint32_t*) value), *((uint32_t*) mask))){ return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); - } - ofl_structs_match_put32m(match, f->header, ntohl(*((uint32_t*) value)), ntohl(*((uint32_t*) mask))); + } + ofl_structs_match_put_pbb_isidm(match, f->header, pbb_isid, (uint8_t*) &pbb_isid_mask); return 0; } case OFI_OXM_OF_TUNNEL_ID:{ @@ -577,7 +582,6 @@ oxm_pull_match(struct ofpbuf *buf, struct ofl_match * match_dst, int match_len) const struct oxm_field *f; int error; f = oxm_field_lookup(header); - if (!f) { error = ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_FIELD); } @@ -719,6 +723,24 @@ oxm_put_64w(struct ofpbuf *buf, uint32_t header, uint64_t value, uint64_t mask) ofpbuf_put(buf, &mask, sizeof mask); } +static void +oxm_put_pbb(struct ofpbuf *buf, uint32_t header, + const uint8_t value[PBB_ISID_LEN]) +{ + oxm_put_header(buf, header); + ofpbuf_put(buf, value, PBB_ISID_LEN); + +} + +static void +oxm_put_pbbm(struct ofpbuf *buf, uint32_t header, + const uint8_t value[PBB_ISID_LEN], const uint8_t mask[PBB_ISID_LEN]) +{ + oxm_put_header(buf, header); + ofpbuf_put(buf, value, PBB_ISID_LEN); + ofpbuf_put(buf, mask, PBB_ISID_LEN); +} + static void oxm_put_eth(struct ofpbuf *buf, uint32_t header, const uint8_t value[ETH_ADDR_LEN]) @@ -872,6 +894,20 @@ int oxm_put_match(struct ofpbuf *buf, struct ofl_match *omt){ } break; } + case (PBB_ISID_LEN):{ + { + uint8_t value[PBB_ISID_LEN]; + memcpy(&value, oft->value, PBB_ISID_LEN); + if(!has_mask) + oxm_put_pbb(buf,oft->header, value); + else { + uint8_t mask[PBB_ISID_LEN]; + memcpy(&mask, oft->value + length ,PBB_ISID_LEN); + oxm_put_pbbm(buf, oft->header,value, mask); + } + break; + } + } case (sizeof(uint32_t)):{ uint32_t value; memcpy(&value, oft->value,sizeof(uint32_t)); diff --git a/oflib/oxm-match.h b/oflib/oxm-match.h index 0e4fde00..c5dbbf8c 100644 --- a/oflib/oxm-match.h +++ b/oflib/oxm-match.h @@ -215,8 +215,8 @@ #define OXM_OF_MPLS_BOS OXM_HEADER (0x8000, 36, 1) -#define OXM_OF_PBB_ISID OXM_HEADER (0x8000, 37, 4) -#define OXM_OF_PBB_ISID_W OXM_HEADER_W (0x8000, 37, 4) +#define OXM_OF_PBB_ISID OXM_HEADER (0x8000, 37, 3) +#define OXM_OF_PBB_ISID_W OXM_HEADER_W (0x8000, 37, 3) #define OXM_OF_TUNNEL_ID OXM_HEADER (0x8000, 38, 8) #define OXM_OF_TUNNEL_ID_W OXM_HEADER_W (0x8000, 38, 8) diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 5de35a04..921c6f5c 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -81,6 +81,7 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) { /*Field existence is guaranteed by the field pre-requisite on matching */ + fprintf(stderr, "Header %d\n", OXM_FIELD(act->field->header)); switch(act->field->header){ case OXM_OF_ETH_DST:{ memcpy(pkt->handle_std->proto->eth->eth_dst, @@ -410,9 +411,9 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) } case OXM_OF_PBB_ISID :{ struct pbb_header *pbb = pkt->handle_std->proto->pbb; - uint32_t v = *((uint32_t*) act->field->value); - pbb->id = (pbb->id & ~ntohl(PBB_ISID_MASK)) | - ntohl(v & PBB_ISID_MASK); + uint8_t* pbb_isid; + pbb_isid = act->field->value; + pbb->id = (pbb->id & 0xFF) | ((pbb_isid[2] << 24) | (pbb_isid[1] << 16) | (pbb_isid[1] << 8)); break; } case OXM_OF_TUNNEL_ID :{ diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 284ce6df..05109604 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -48,7 +48,7 @@ match_8(uint8_t *a, uint8_t *b) { /* Returns true if two masked 8 bit values match */ static inline bool match_mask8(uint8_t *a, uint8_t *am, uint8_t *b) { - return ((~(am[0]) & (a[0] ^ b[0])) == 0); + return (((am[0]) & (a[0] ^ b[0])) == 0); } /* Returns true if two 16 bit values match */ @@ -68,6 +68,20 @@ match_mask16(uint8_t *a, uint8_t *am, uint8_t *b) { return (((mask) & (*a1 ^ *b1)) == 0); } +/* Returns true if two 24 bit values match */ +static inline bool +match_24(uint8_t *a, uint8_t *b) { + return (match_16(a, b) && + match_8(a+2, b+2)); +} + +/* Returns true if two masked 24 bit values match */ +static inline bool +match_mask24(uint8_t *a, uint8_t *am, uint8_t *b) { + return (match_mask16(a, am, b) && + match_mask8(a+2, am+2, b+2)); +} + /* Returns true if two 32 bit values match */ static inline bool match_32(uint8_t *a, uint8_t *b) { @@ -228,6 +242,16 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ break; } break; + case 3: + if (has_mask) { + if (!match_mask24(flow_val, flow_mask, packet_val)) + return false; + } + else { + if (!match_24(flow_val, packet_val)) + return false; + } + break; case 4: if (has_mask) { if (!match_mask32(flow_val, flow_mask, packet_val)) @@ -292,6 +316,12 @@ strict_mask16(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & ~(*mask_a))) == 0; } +static inline bool +strict_mask24(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { + return strict_mask16(a, b, am, bm) && + strict_mask8(a+2, b+2, am+2, bm+2); +} + static inline bool strict_mask32(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint32_t *a1 = (uint32_t *) a; @@ -389,6 +419,16 @@ match_std_strict(struct ofl_match *a, struct ofl_match *b) { return false; } break; + case 3: + if (has_mask) { + if (!strict_mask24(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + return false; + } + else { + if (!match_24(flow_mod_val, flow_entry_val)) + return false; + } + break; case 4: if (has_mask) { if (!strict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) @@ -457,6 +497,12 @@ nonstrict_mask16(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { return (~(*mask_a) & (~(*a1) | ~(*b1) | *mask_b) & (*a1| *b1 | *mask_b)) == 0; } +static inline bool +nonstrict_mask24(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { + return nonstrict_mask16(a, b, am, bm) && + nonstrict_mask8(a+2, b+2, am+2, bm+2); +} + static inline bool nonstrict_mask32(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint32_t *a1 = (uint32_t *) a; @@ -551,6 +597,16 @@ match_std_nonstrict(struct ofl_match *a, struct ofl_match *b) return false; } break; + case 3: + if (has_mask) { + if (!nonstrict_mask24(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + return false; + } + else { + if (!match_24(flow_mod_val, flow_entry_val)) + return false; + } + break; case 4: if (has_mask) { if (!nonstrict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) From 0ce861bd40bc46923f4c790325164c00cf3d6e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Wed, 17 Dec 2014 00:45:05 -0200 Subject: [PATCH 104/191] Apply DSCP remark for IPv6 packets. --- udatapath/meter_entry.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index 8a4db8d1..b4f42dc1 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -226,9 +226,9 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ break; } case OFPMBT_DSCP_REMARK:{ - /* Nothing prevent this band to be used for non-IP packets, so filter them out. Jean II */ + struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; + /* Nothing prevent this band to be used for non-IP packets, so filter them out. Jean II */ if ((*pkt)->handle_std->proto->ipv4 != NULL) { - struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; // Fetch dscp in ipv4 header struct ip_header *ipv4 = (*pkt)->handle_std->proto->ipv4; uint8_t old_drop = ipv4->ip_tos & 0x1C; @@ -239,7 +239,7 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ drop precedence is low (tos 0x***010**) or medium (tos 0x***100**). Jean II */ if (((old_drop == 0x8) && (band_header->prec_level <= 2)) || ((old_drop == 0x10) && (band_header->prec_level <= 1))) { - uint8_t new_drop = old_drop + (band_header->prec_level << 3); + uint8_t new_drop = old_drop + (band_header->prec_level << 3); uint8_t new_tos = new_drop | (ipv4->ip_tos & 0xE3); uint16_t old_val = htons((ipv4->ip_ihl_ver << 8) + ipv4->ip_tos); uint16_t new_val = htons((ipv4->ip_ihl_ver << 8) + new_tos); @@ -247,8 +247,18 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ ipv4->ip_tos = new_tos; } } + else if ((*pkt)->handle_std->proto->ipv6 != NULL){ + struct ipv6_header *ipv6 = (*pkt)->handle_std->proto->ipv6; + uint32_t ipv6_ver_tc_fl = ntohl(ipv6->ipv6_ver_tc_fl); + uint32_t old_drop = ipv6_ver_tc_fl & 0x1C00000; + if (((old_drop == 0x800000) && (band_header->prec_level <= 2)) || ((old_drop == 0x1000000) && (band_header->prec_level <= 1))){ + uint32_t prec_level = band_header->prec_level << 23; + uint32_t new_drop = old_drop + prec_level; + ipv6->ipv6_ver_tc_fl = htonl(new_drop | (ipv6_ver_tc_fl & 0xFE3FFFFF)); + } + } break; - } + } case OFPMBT_EXPERIMENTER:{ break; } From c9fa3941e0545db0b50df4cfd677a766ab07d57c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Wed, 17 Dec 2014 18:13:03 -0200 Subject: [PATCH 105/191] Fix IPv4 ecn packet parsing. This commit removes wrong byte shifting. --- nbee_link/nbee_link.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index 04dc4416..97fa060e 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -254,7 +254,7 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str uint8_t m_value; if (strcmp(field->Name, "ip ecn") == 0){ sscanf(field->Value, "%hhx", &m_value); - m_value = (m_value & IP_ECN_MASK) >> IPV6_ECN_SHIFT; + m_value = (m_value & IP_ECN_MASK); ofl_structs_match_put8(pktout, header, m_value); } else { From b17c74e56122d7e834dd31aaec4eab421b294127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Wed, 17 Dec 2014 18:16:43 -0200 Subject: [PATCH 106/191] Add matching of masked vlan_id field. This commit adds the missing case of matching flows with a masked vlan_id field. --- udatapath/match_std.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 05109604..63d7c809 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -64,8 +64,8 @@ static inline bool match_mask16(uint8_t *a, uint8_t *am, uint8_t *b) { uint16_t *a1 = (uint16_t *) a; uint16_t *b1 = (uint16_t *) b; - uint16_t mask = (uint16_t) ((uint8_t) ~am[0] << 8 | (uint8_t) ~a[1]); - return (((mask) & (*a1 ^ *b1)) == 0); + uint16_t *mask = (uint16_t*) am; + return (((*mask) & (*a1 ^ *b1)) == 0); } /* Returns true if two 24 bit values match */ @@ -214,9 +214,17 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ /* Any VLAN ID is acceptable. No further checks */ } else { /* Check the VLAN ID */ - *flow_vlan_id &= VLAN_VID_MASK; - if (!match_16(flow_val, packet_val)) - return false; + *flow_vlan_id &= VLAN_VID_MASK; + if (has_mask){ + if (!match_mask16(flow_val, flow_mask, packet_val)){ + return false; + } + } + else { + if (!match_16(flow_val, packet_val)){ + return false; + } + } } break; } From 80ffd77e6ce15854e5bcab913acbbd7d45c8e129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Wed, 17 Dec 2014 18:27:46 -0200 Subject: [PATCH 107/191] Fix the multiple vlan push. This commit adds a slightly change to the vlan tag reconstruction to reconsider the case when there is another vlan tag after the one being reconstructed. --- lib/netdev.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/netdev.c b/lib/netdev.c index ae7fec51..b79c3836 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -993,7 +993,7 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { struct tpacket_auxdata *aux; struct vlan_tag *tag; - + uint16_t eth_type; buffer->size += n_bytes; if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) || @@ -1006,11 +1006,13 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) continue; /* VLAN tag found. Shift MAC addresses down and insert VLAN tag */ /* Create headroom for the VLAN tag */ - uint16_t* eth_type = (uint16_t *)(buffer->data + ETHER_ADDR_LEN * 2); + eth_type = ntohs(*((uint16_t *)(buffer->data + ETHER_ADDR_LEN * 2))); ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN); memmove(buffer->data, (uint8_t*)buffer->data+VLAN_HEADER_LEN, ETH_ALEN * 2); tag = (struct vlan_tag *)((uint8_t*)buffer->data + ETH_ALEN * 2); - if (ntohs(*eth_type) == ETH_TYPE_VLAN_PBB_S){ + if (eth_type == ETH_TYPE_VLAN_PBB_S || + eth_type == ETH_TYPE_VLAN_PBB_B || + eth_type == ETH_TYPE_VLAN){ tag->vlan_tp_id = htons(ETH_TYPE_VLAN_PBB_B); } else { From 58fc961d3ae922cbec2e01927ccc7e2d7547ae9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Wed, 17 Dec 2014 18:32:26 -0200 Subject: [PATCH 108/191] Fix vlan pcp parsing. --- nbee_link/nbee_link.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index 97fa060e..33916abf 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -231,10 +231,11 @@ int nblink_extract_proto_fields(struct ofpbuf * pktin, _nbPDMLField * field, str ofl_structs_match_put16(pktout, header, m_value); } else if (header == OXM_OF_VLAN_PCP){ - uint8_t m_value; - sscanf(field->Value, "%hhx", &m_value); - m_value = (m_value & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT; - ofl_structs_match_put8(pktout, header, m_value); + uint16_t m_value; + uint8_t vlan_pcp; + sscanf(field->Value, "%hx", &m_value); + vlan_pcp = (m_value & VLAN_PCP_MASK) >> VLAN_PCP_SHIFT; + ofl_structs_match_put8(pktout, header, vlan_pcp); } else if(header == OXM_OF_IP_DSCP){ uint8_t m_value; From 355e0fdc7366218351e4e364b9882618512d22e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Wed, 17 Dec 2014 20:41:33 -0200 Subject: [PATCH 109/191] Fix match_mask32. This commit fixes the cast of the mask for matching masked 32 bits fields. --- udatapath/match_std.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 63d7c809..26bae356 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -95,9 +95,8 @@ static inline bool match_mask32(uint8_t *a, uint8_t *am, uint8_t *b) { uint32_t *a1 = (uint32_t *) a; uint32_t *b1 = (uint32_t *) b; - uint32_t mask = (uint32_t) ((uint8_t) ~am[0] << 24 | (uint8_t) ~am[1] << 16 - | (uint8_t) ~am[2] << 8 | (uint8_t) ~am[3]); - return (((mask) & (*a1 ^ *b1)) == 0); + uint32_t *mask = (uint32_t*) am; + return (((*mask) & (*a1 ^ *b1)) == 0); } /* Returns true if two 48 bit values match */ From 16b60b73574339c603f32906c6ee4513e0322fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 8 Jan 2015 09:22:38 -0200 Subject: [PATCH 110/191] Update README.md Fix directory name. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cc7246be..c86e2197 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ The switch makes use of the NetBee library to parse packets, so we need to insta ``` ## Building -Run the following commands in the `of13softswitch` directory to build and install everything: +Run the following commands in the `ofsoftswitch13` directory to build and install everything: $ ./boot.sh $ ./configure From 377add0a4b392abaa9503877e5a253ba0905d40a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 23 Feb 2015 01:11:46 -0300 Subject: [PATCH 111/191] Fix generation id check. This commit fixes the generation id casting to the operation to the correct type. --- udatapath/datapath.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 6343a466..6356549f 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -591,8 +591,9 @@ dp_handle_set_desc(struct datapath *dp, struct ofl_exp_openflow_msg_set_dp_desc static ofl_err dp_check_generation_id(struct datapath *dp, uint64_t new_gen_id){ - if(dp->generation_id >= 0 && ((uint64_t)(new_gen_id - dp->generation_id) < 0) ) + if(dp->generation_id >= 0 && ((int64_t)(new_gen_id - dp->generation_id) < 0) ){ return ofl_error(OFPET_ROLE_REQUEST_FAILED, OFPRRFC_STALE); + } else dp->generation_id = new_gen_id; return 0; From b4ccf1b4ef59f04c27f824c433ec44f051dbc559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 23 Feb 2015 01:13:46 -0300 Subject: [PATCH 112/191] Do not allow packet_out with OFP_NO_BUFFER without packet data. According to the specification: "when buffer_id is OFP_NO_BUFFER the data field contains the packet to be processed" The specification does not specify how the switch must handle packet_out messages with buffer id OFP_NO_BUFFER. Thus, in the switch we are raising an error message of type OFPET_BAD_REQUEST, with code OFPBRC_BAD_PACKET. --- udatapath/dp_control.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/udatapath/dp_control.c b/udatapath/dp_control.c index 2cfde9ed..d9a6b75d 100644 --- a/udatapath/dp_control.c +++ b/udatapath/dp_control.c @@ -126,10 +126,9 @@ handle_control_packet_out(struct datapath *dp, struct ofl_msg_packet_out *msg, const struct sender *sender) { struct packet *pkt; int error; - - if(sender->remote->role == OFPCR_ROLE_SLAVE) + if(sender->remote->role == OFPCR_ROLE_SLAVE){ return ofl_error(OFPET_BAD_REQUEST, OFPBRC_IS_SLAVE); - + } error = dp_actions_validate(dp, msg->actions_num, msg->actions); if (error) { return error; @@ -137,11 +136,15 @@ handle_control_packet_out(struct datapath *dp, struct ofl_msg_packet_out *msg, if (msg->buffer_id == NO_BUFFER) { struct ofpbuf *buf; + /* If there is no packet in the message, send error message */ + if (!msg->data_length){ + return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_PACKET); + } /* NOTE: the created packet will take the ownership of data in msg. */ buf = ofpbuf_new(0); ofpbuf_use(buf, msg->data, msg->data_length); - ofpbuf_put_uninit(buf, msg->data_length); - pkt = packet_create(dp, msg->in_port, buf, true); + ofpbuf_put_uninit(buf, msg->data_length); + pkt = packet_create(dp, msg->in_port, buf, true); } else { /* NOTE: in this case packet should not have data */ pkt = dp_buffers_retrieve(dp->buffers, msg->buffer_id); @@ -155,7 +158,7 @@ handle_control_packet_out(struct datapath *dp, struct ofl_msg_packet_out *msg, dp_execute_action_list(pkt, msg->actions_num, msg->actions, 0xffffffffffffffff); packet_destroy(pkt); - ofl_msg_free_packet_out(msg, false, dp->exp); + ofl_msg_free_packet_out(msg, false, dp->exp); return 0; } From cb740bd2565ac7e5d61ebe30ee75160a5452a033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 23 Feb 2015 18:42:49 -0300 Subject: [PATCH 113/191] Add flags member to ofp_flow_stats. Fix missing flags field in the response of a flow stats request. --- include/openflow/openflow.h | 3 ++- oflib/ofl-structs-pack.c | 3 ++- oflib/ofl-structs-unpack.c | 1 + oflib/ofl-structs.h | 1 + udatapath/flow_entry.c | 1 + 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index cd28aabc..e72f2801 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -1000,7 +1000,8 @@ struct ofp_flow_stats { uint16_t priority; /* Priority of the 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. */ + uint16_t flags; /* One of OFPFF_*/ + uint8_t pad2[4]; /* 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. */ diff --git a/oflib/ofl-structs-pack.c b/oflib/ofl-structs-pack.c index 2ea85b02..376741fa 100644 --- a/oflib/ofl-structs-pack.c +++ b/oflib/ofl-structs-pack.c @@ -543,7 +543,8 @@ ofl_structs_flow_stats_pack(struct ofl_flow_stats *src, uint8_t *dst, struct ofl flow_stats->priority = htons(src->priority); flow_stats->idle_timeout = htons(src->idle_timeout); flow_stats->hard_timeout = htons(src->hard_timeout); - memset(flow_stats->pad2, 0x00, 6); + flow_stats->flags = htons(src->flags); + memset(flow_stats->pad2, 0x00, 4); flow_stats->cookie = hton64(src->cookie); flow_stats->packet_count = hton64(src->packet_count); flow_stats->byte_count = hton64(src->byte_count); diff --git a/oflib/ofl-structs-unpack.c b/oflib/ofl-structs-unpack.c index 19ada818..17442af2 100644 --- a/oflib/ofl-structs-unpack.c +++ b/oflib/ofl-structs-unpack.c @@ -522,6 +522,7 @@ ofl_structs_flow_stats_unpack(struct ofp_flow_stats *src, uint8_t *buf, size_t * s->priority = ntohs( src->priority); s->idle_timeout = ntohs( src->idle_timeout); s->hard_timeout = ntohs( src->hard_timeout); + s->flags = ntohs( src->flags); s->cookie = ntoh64(src->cookie); s->packet_count = ntoh64(src->packet_count); s->byte_count = ntoh64(src->byte_count); diff --git a/oflib/ofl-structs.h b/oflib/ofl-structs.h index ca2f867e..94209ed5 100644 --- a/oflib/ofl-structs.h +++ b/oflib/ofl-structs.h @@ -154,6 +154,7 @@ struct ofl_flow_stats { uint16_t idle_timeout; /* Number of seconds idle before expiration. */ uint16_t hard_timeout; /* Number of seconds before expiration. */ + uint16_t flags; /* One of OFPFF_*/ 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. */ diff --git a/udatapath/flow_entry.c b/udatapath/flow_entry.c index e361d982..0031f966 100644 --- a/udatapath/flow_entry.c +++ b/udatapath/flow_entry.c @@ -344,6 +344,7 @@ flow_entry_create(struct datapath *dp, struct flow_table *table, struct ofl_msg_ entry->stats->priority = mod->priority; entry->stats->idle_timeout = mod->idle_timeout; entry->stats->hard_timeout = mod->hard_timeout; + entry->stats->flags = mod->flags; entry->stats->cookie = mod->cookie; entry->no_pkt_count = ((mod->flags & OFPFF_NO_PKT_COUNTS) != 0 ); entry->no_byt_count = ((mod->flags & OFPFF_NO_BYT_COUNTS) != 0 ); From 1e3c9c464526f2e75fbec329772e5e70a9058a6c Mon Sep 17 00:00:00 2001 From: Viktor Nordell Date: Fri, 27 Feb 2015 11:50:39 +0100 Subject: [PATCH 114/191] Fix double free. pipeline_process_packet() takes ownership of packet, which is not assumed by dp_actions_output_port(). This causes action_set_execute to double free the structure. --- udatapath/dp_actions.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index 921c6f5c..e53ec858 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -1086,8 +1086,11 @@ dp_actions_output_port(struct packet *pkt, uint32_t out_port, uint32_t out_queue case (OFPP_TABLE): { if (pkt->packet_out) { // NOTE: hackish; makes sure packet cannot be resubmit to pipeline again. - pkt->packet_out = false; - pipeline_process_packet(pkt->dp->pipeline, pkt); + // pipeline_process_packet takes overship of the packet, we need a copy. + struct packet *pkt_copy = packet_clone(pkt); + + pkt_copy->packet_out = false; + pipeline_process_packet(pkt->dp->pipeline, pkt_copy); } else { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to resubmit packet to pipeline."); } From 0b41e80eea62171592413910fe1d7c157a2c12cc Mon Sep 17 00:00:00 2001 From: Viktor Nordell Date: Wed, 4 Mar 2015 11:07:25 +0100 Subject: [PATCH 115/191] Fix bug in VID handling. Fixed a bug where OFPVID_PRESENT values would be removed from flow table entries. This occurred in the packet pipeline, where packet_match would remove the value. Caused for example flowmod deletes to fail. --- udatapath/match_std.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 26bae356..567264a8 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -205,22 +205,22 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ switch (packet_header) { case OXM_OF_VLAN_VID: { /* Special handling for VLAN ID */ - uint16_t *flow_vlan_id = (uint16_t*) flow_val; - if (*flow_vlan_id == OFPVID_NONE) { + uint16_t flow_vlan_id = *((uint16_t*) flow_val); + if (flow_vlan_id == OFPVID_NONE) { /* Packet has a VLAN tag when none should be there */ return false; - } else if (*flow_vlan_id == OFPVID_PRESENT) { + } else if (flow_vlan_id == OFPVID_PRESENT) { /* Any VLAN ID is acceptable. No further checks */ } else { /* Check the VLAN ID */ - *flow_vlan_id &= VLAN_VID_MASK; + flow_vlan_id &= VLAN_VID_MASK; if (has_mask){ - if (!match_mask16(flow_val, flow_mask, packet_val)){ + if (!match_mask16((uint8_t*) &flow_vlan_id, flow_mask, packet_val)){ return false; } } else { - if (!match_16(flow_val, packet_val)){ + if (!match_16((uint8_t*) &flow_vlan_id, packet_val)){ return false; } } From c31d2a1c84dbb690aca4c99fdd7222fde712fba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Wed, 25 Mar 2015 21:40:24 -0300 Subject: [PATCH 116/191] Fix strict masked ip matching. Quick and dirty hack to stop different IP addresses, with equal masks, to match. The problem is caused because we work with IP addresses in the network byte order format and the function strict_match32 performs matching on values in the host byte order. Thus, in little endian machines, the function will not work. Problems like this show that the match needs a huge refactoring. --- udatapath/match_std.c | 63 +++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 567264a8..1108953b 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -338,6 +338,15 @@ strict_mask32(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & ~(*mask_a))) == 0; } +static inline bool +strict_mask_ip(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { + uint32_t *a1 = (uint32_t *) a; + uint32_t *b1 = (uint32_t *) b; + uint32_t *mask_a = (uint32_t *) am; + uint32_t *mask_b = (uint32_t *) bm; + return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & (*mask_a))) == 0; +} + static inline bool strict_mask48(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { return strict_mask32(a, b, am, bm) && @@ -375,6 +384,7 @@ match_std_strict(struct ofl_match *a, struct ofl_match *b) { int field_len; uint8_t *flow_mod_val, *flow_mod_mask=0; uint8_t *flow_entry_val, *flow_entry_mask=0; + uint8_t oxm_field; bool has_mask; /* Both matches all wildcarded */ @@ -395,6 +405,7 @@ match_std_strict(struct ofl_match *a, struct ofl_match *b) { } /* At this point match length and has_mask are equal */ + oxm_field = OXM_FIELD(flow_mod_match->header); has_mask = OXM_HASMASK(flow_mod_match->header); field_len = OXM_LENGTH(flow_mod_match->header); flow_mod_val = flow_mod_match->value; @@ -408,22 +419,26 @@ match_std_strict(struct ofl_match *a, struct ofl_match *b) { switch (field_len) { case 1: if (has_mask) { - if (!strict_mask8(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + if (!strict_mask8(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_8(flow_mod_val, flow_entry_val)) + if (!match_8(flow_mod_val, flow_entry_val)){ return false; + } } break; case 2: if (has_mask) { - if (!strict_mask16(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + if (!strict_mask16(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_16(flow_mod_val, flow_entry_val)) + if (!match_16(flow_mod_val, flow_entry_val)){ return false; + } } break; case 3: @@ -431,49 +446,69 @@ match_std_strict(struct ofl_match *a, struct ofl_match *b) { if (!strict_mask24(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) return false; } - else { - if (!match_24(flow_mod_val, flow_entry_val)) + else { + if (!match_24(flow_mod_val, flow_entry_val)){ return false; + } } break; case 4: if (has_mask) { - if (!strict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + /* Quick and dirty fix for IP addresses matching + TODO: Matching needs a huge refactoring */ + if (oxm_field == OFPXMT_OFB_IPV4_SRC || + oxm_field == OFPXMT_OFB_IPV4_DST || + oxm_field == OFPXMT_OFB_ARP_SPA || + oxm_field == OFPXMT_OFB_ARP_TPA) { + if (!strict_mask_ip(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ + return false; + } + } + if (!strict_mask32(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_32(flow_mod_val, flow_entry_val)) + + if (!match_32(flow_mod_val, flow_entry_val)){ return false; + } } break; case 6: if (has_mask) { - if (!strict_mask48(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + if (!strict_mask48(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_48(flow_mod_val, flow_entry_val)) + if (!match_48(flow_mod_val, flow_entry_val)){ return false; + } } break; case 8: if (has_mask) { - if (!strict_mask64(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + if (!strict_mask64(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_64(flow_mod_val, flow_entry_val)) + if (!match_64(flow_mod_val, flow_entry_val)){ return false; + } } break; case 16: if (has_mask) { - if (!strict_mask128(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)) + if (!strict_mask128(flow_mod_val, flow_entry_val, flow_mod_mask, flow_entry_mask)){ return false; + } } else { - if (!match_128(flow_mod_val, flow_entry_val)) + if (!match_128(flow_mod_val, flow_entry_val)){ return false; + } } break; default: From 936696eb955f68ca1c4da5d6b209ce9038362328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 2 Apr 2015 19:29:31 -0300 Subject: [PATCH 117/191] Fix network byte order on pack and unpack of get/set async message. Correct the byte order of the message fields. --- oflib/ofl-messages-pack.c | 6 +++--- oflib/ofl-messages-unpack.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/oflib/ofl-messages-pack.c b/oflib/ofl-messages-pack.c index 234f865e..6c57e9bc 100644 --- a/oflib/ofl-messages-pack.c +++ b/oflib/ofl-messages-pack.c @@ -365,9 +365,9 @@ ofl_msg_pack_async_config(struct ofl_msg_async_config *msg, uint8_t **buf, size_ ac = (struct ofp_async_config*)(*buf); for(i = 0; i < 2; i++){ - ac->packet_in_mask[i] = msg->config->packet_in_mask[i]; - ac->port_status_mask[i] = msg->config->port_status_mask[i]; - ac->flow_removed_mask[i] = msg->config->flow_removed_mask[i]; + ac->packet_in_mask[i] = htonl(msg->config->packet_in_mask[i]); + ac->port_status_mask[i] = htonl(msg->config->port_status_mask[i]); + ac->flow_removed_mask[i] = htonl(msg->config->flow_removed_mask[i]); } return 0; } diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 9c77c96c..a13ec519 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -201,9 +201,9 @@ ofl_msg_unpack_async_config(struct ofp_header *src, size_t *len, struct ofl_msg_ dac = (struct ofl_msg_async_config*)malloc(sizeof(struct ofl_msg_async_config)); dac->config = (struct ofl_async_config*) malloc(sizeof(struct ofl_async_config)); for(i = 0; i < 2; i++){ - dac->config->packet_in_mask[i] = sac->packet_in_mask[i]; - dac->config->port_status_mask[i] = sac->port_status_mask[i]; - dac->config->flow_removed_mask[i] = sac->flow_removed_mask[i]; + dac->config->packet_in_mask[i] = ntohl(sac->packet_in_mask[i]); + dac->config->port_status_mask[i] = ntohl(sac->port_status_mask[i]); + dac->config->flow_removed_mask[i] = ntohl(sac->flow_removed_mask[i]); } *msg = (struct ofl_msg_header*)dac; From bc63546f7fb19acebb6d8b7735b468f9e63c4795 Mon Sep 17 00:00:00 2001 From: Mahdth Date: Tue, 12 May 2015 15:52:33 +0200 Subject: [PATCH 118/191] Update meter_entry.c Update fields after applying DSCP Remark metering --- udatapath/meter_entry.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index e0714bad..42668c09 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -226,6 +226,9 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ break; } case OFPMBT_DSCP_REMARK:{ + packet_handle_std_validate(pkt->handle_std); + if (pkt->handle_std->valid) + { struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; /* Nothing prevent this band to be used for non-IP packets, so filter them out. Jean II */ if ((*pkt)->handle_std->proto->ipv4 != NULL) { @@ -257,6 +260,8 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ ipv6->ipv6_ver_tc_fl = htonl(new_drop | (ipv6_ver_tc_fl & 0xFE3FFFFF)); } } + pkt->handle_std->valid = false; + } break; } case OFPMBT_EXPERIMENTER:{ From 5dc3d2f6837d3fc984c526c6dddba86337c0affe Mon Sep 17 00:00:00 2001 From: Mahdth Date: Tue, 12 May 2015 22:11:46 +0200 Subject: [PATCH 119/191] Update meter_entry.c --- udatapath/meter_entry.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index 42668c09..0d09a63b 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -226,8 +226,8 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ break; } case OFPMBT_DSCP_REMARK:{ - packet_handle_std_validate(pkt->handle_std); - if (pkt->handle_std->valid) + packet_handle_std_validate((*pkt)->handle_std); + if ((*pkt)->handle_std->valid) { struct ofl_meter_band_dscp_remark *band_header = (struct ofl_meter_band_dscp_remark *) entry->config->bands[b]; /* Nothing prevent this band to be used for non-IP packets, so filter them out. Jean II */ @@ -260,7 +260,7 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ ipv6->ipv6_ver_tc_fl = htonl(new_drop | (ipv6_ver_tc_fl & 0xFE3FFFFF)); } } - pkt->handle_std->valid = false; + (*pkt)->handle_std->valid = false; } break; } From e2c05d7ac8a9ebd75493dd7b6ce109a355b8371d Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Sun, 17 May 2015 16:12:29 -0300 Subject: [PATCH 120/191] This commit fix bug #172, with proper asynchronous configuration check. --- udatapath/datapath.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 6356549f..89a0de76 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -487,20 +487,20 @@ send_openflow_buffer(struct datapath *dp, struct ofpbuf *buffer, continue; if((p->reason == OFPPR_DELETE) && !(r->config.port_status_mask[0] & 0x2)) continue; - if((p->reason == OFPPR_MODIFY) && !(r->config.packet_in_mask[0] & 0x4)) + if((p->reason == OFPPR_MODIFY) && !(r->config.port_status_mask[0] & 0x4)) continue; } case (OFPT_FLOW_REMOVED):{ struct ofp_flow_removed *p= (struct ofp_flow_removed *)buffer->data; - if((p->reason == OFPRR_IDLE_TIMEOUT) && !(r->config.port_status_mask[0] & 0x1)) + if((p->reason == OFPRR_IDLE_TIMEOUT) && !(r->config.flow_removed_mask[0] & 0x1)) continue; - if((p->reason == OFPRR_HARD_TIMEOUT) && !(r->config.port_status_mask[0] & 0x2)) + if((p->reason == OFPRR_HARD_TIMEOUT) && !(r->config.flow_removed_mask[0] & 0x2)) continue; - if((p->reason == OFPRR_DELETE) && !(r->config.packet_in_mask[0] & 0x4)) + if((p->reason == OFPRR_DELETE) && !(r->config.flow_removed_mask[0] & 0x4)) continue; - if((p->reason == OFPRR_GROUP_DELETE) && !(r->config.packet_in_mask[0] & 0x8)) + if((p->reason == OFPRR_GROUP_DELETE) && !(r->config.flow_removed_mask[0] & 0x8)) continue; - if((p->reason == OFPRR_METER_DELETE) && !(r->config.packet_in_mask[0] & 0x10)) + if((p->reason == OFPRR_METER_DELETE) && !(r->config.flow_removed_mask[0] & 0x10)) continue; } } @@ -517,7 +517,7 @@ send_openflow_buffer(struct datapath *dp, struct ofpbuf *buffer, continue; if((p->reason == OFPPR_DELETE) && !(r->config.port_status_mask[1] & 0x2)) continue; - if((p->reason == OFPPR_MODIFY) && !(r->config.packet_in_mask[1] & 0x4)) + if((p->reason == OFPPR_MODIFY) && !(r->config.port_status_mask[1] & 0x4)) continue; } } From 41cb72dbbd40dd5418177bea22fea3d2f8802e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Tue, 19 May 2015 21:02:02 -0300 Subject: [PATCH 121/191] Fix segmentation fault when handling packets larger than MTU. This commit fixes the switch segmenation fault when packets larger than the interface MTU are received. The problem is caused mainly due to TCP segmentation offload, which enables the TCP stack to send an entire chunk of data to be break up by the network interface. While the switch does not break anymore, it still does not handle TSO, so larger packets might be dropped when sent to the switch causing loss of performance. For this reason is still recommended to disable TSO support on the interface. --- lib/dhcp-client.c | 4 ++-- lib/netdev.c | 14 ++++++-------- lib/netdev.h | 2 +- udatapath/dp_ports.c | 9 ++------- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/lib/dhcp-client.c b/lib/dhcp-client.c index 3c7b33da..39a6b06d 100644 --- a/lib/dhcp-client.c +++ b/lib/dhcp-client.c @@ -931,7 +931,7 @@ do_receive_msg(struct dhclient *cli, struct dhcp_msg *msg) int error; ofpbuf_clear(&b); - error = netdev_recv(cli->netdev, &b); + error = netdev_recv(cli->netdev, &b, 0); if (error) { goto drained; } @@ -1047,7 +1047,7 @@ do_send_msg(struct dhclient *cli, const struct dhcp_msg *msg) } else { VLOG_INFO(LOG_MODULE, "sending %s", dhcp_type_name(msg->type)); } - error = netdev_send(cli->netdev, &b, 0); + error = netdev_send(cli->netdev, &b, ETH_TOTAL_MAX); if (error) { VLOG_ERR(LOG_MODULE, "send failed on %s: %s", netdev_get_name(cli->netdev), strerror(error)); diff --git a/lib/netdev.c b/lib/netdev.c index b79c3836..5352e730 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -916,7 +916,7 @@ pad_to_minimum_length(struct ofpbuf *buffer) * be returned. */ int -netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) +netdev_recv(struct netdev *netdev, struct ofpbuf *buffer, size_t max_mtu) { #ifdef HAVE_PACKET_AUXDATA @@ -951,7 +951,7 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) msg.msg_controllen = sizeof(cmsg_buf); msg.msg_flags = 0; - iov.iov_len = buffer->allocated; + iov.iov_len = max_mtu; iov.iov_base = buffer->data; #else @@ -976,7 +976,6 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) n_bytes = recvfrom(netdev->tap_fd, ofpbuf_tail(buffer), (ssize_t)ofpbuf_tailroom(buffer), 0, (struct sockaddr *)&sll, &sll_len); - #endif /* ifdef HAVE_PACKET_AUXDATA */ } while (n_bytes < 0 && errno == EINTR); } @@ -1002,8 +1001,9 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) continue; } aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg); - if (aux->tp_vlan_tci == 0) + if (aux->tp_vlan_tci == 0){ continue; + } /* VLAN tag found. Shift MAC addresses down and insert VLAN tag */ /* Create headroom for the VLAN tag */ eth_type = ntohs(*((uint16_t *)(buffer->data + ETHER_ADDR_LEN * 2))); @@ -1027,15 +1027,14 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer) if (sll.sll_pkttype == PACKET_OUTGOING) { return EAGAIN; } - buffer->size += n_bytes; - + buffer->size += n_bytes; +#endif /* When the kernel internally sends out an Ethernet frame on an * interface, it gives us a copy *before* padding the frame to the * minimum length. Thus, when it sends out something like an ARP * request, we see a too-short frame. So pad it out to the minimum * length. */ pad_to_minimum_length(buffer); -#endif return 0; } @@ -1085,7 +1084,6 @@ netdev_send(struct netdev *netdev, const struct ofpbuf *buffer, do { n_bytes = write(netdev->queue_fd[class_id], buffer->data, buffer->size); } while (n_bytes < 0 && errno == EINTR); - if (n_bytes < 0) { /* The Linux AF_PACKET implementation never blocks waiting for room * for packets, instead returning ENOBUFS. Translate this into EAGAIN diff --git a/lib/netdev.h b/lib/netdev.h index b1937bb2..b55c6c45 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -76,7 +76,7 @@ int netdev_open(const char *name, int ethertype, struct netdev **); int netdev_open_tap(const char *name, struct netdev **); void netdev_close(struct netdev *); -int netdev_recv(struct netdev *, struct ofpbuf *); +int netdev_recv(struct netdev *, struct ofpbuf *, size_t); void netdev_recv_wait(struct netdev *); int netdev_drain(struct netdev *); int netdev_send(struct netdev *, const struct ofpbuf *, uint16_t class_id); diff --git a/udatapath/dp_ports.c b/udatapath/dp_ports.c index 6122607d..ea915ab1 100644 --- a/udatapath/dp_ports.c +++ b/udatapath/dp_ports.c @@ -269,13 +269,9 @@ dp_ports_run(struct datapath *dp) { * 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; - buffer = ofpbuf_new_with_headroom(hard_header + max_mtu, headroom); - } - error = netdev_recv(p->netdev, buffer); - if (error == ENETDOWN){ - VLOG_ERR(LOG_MODULE, "Não tenho nada mas tô aqui..."); + buffer = ofpbuf_new_with_headroom(VLAN_ETH_HEADER_LEN + max_mtu, headroom); } + error = netdev_recv(p->netdev, buffer, VLAN_ETH_HEADER_LEN + max_mtu); if (!error) { p->stats->rx_packets++; p->stats->rx_bytes += buffer->size; @@ -655,7 +651,6 @@ dp_ports_output_all(struct datapath *dp, struct ofpbuf *buffer, int in_port, boo if (flood && p->conf->config & OFPPC_NO_FWD) { continue; } - dp_ports_output(dp, buffer, p->stats->port_no, 0); } From a30149a0a4d4c3de9318aa9fad27665351ff625f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 21 May 2015 13:43:01 -0300 Subject: [PATCH 122/191] Minor refactor to meter token bucket. This commit modified the token bucket capacity unity. Previously the code considered tokens in Kbps. For this reason the packet size, which is presented in bytes, value was also converted. This packet size convertion was wrong, because small packets sizes were truncated to 0 in Kbps preventing token remotion. The code now changes the bucket capacity and packet conversion to bits. It avoids divisions and eliminates errors of truncation. --- udatapath/datapath.c | 2 +- udatapath/meter_entry.c | 38 ++++++++++++++++---------------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 89a0de76..4053c411 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -195,7 +195,7 @@ dp_run(struct datapath *dp) { pipeline_timeout(dp->pipeline); } - poll_timer_wait(1000); + poll_timer_wait(100); dp_ports_run(dp); /* Talk to remotes. */ diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index 0d09a63b..5820c13b 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -167,7 +167,7 @@ static bool consume_tokens(struct ofl_meter_band_stats *band, uint16_t meter_flag, struct packet *pkt){ if(meter_flag & OFPMF_KBPS){ - uint32_t pkt_size = (pkt->buffer->size*8)/1024; + uint32_t pkt_size = pkt->buffer->size * 8; if (band->tokens >= pkt_size) { band->tokens -= pkt_size; return true; @@ -196,7 +196,6 @@ choose_band(struct meter_entry *entry, struct packet *pkt) for(i = 0; i < entry->stats->meter_bands_num; i++) { struct ofl_meter_band_header *band_header = entry->config->bands[i]; - if(!consume_tokens(entry->stats->band_stats[i], entry->config->flags, pkt) && band_header->rate > tmp_rate) { tmp_rate = band_header->rate; @@ -206,8 +205,7 @@ choose_band(struct meter_entry *entry, struct packet *pkt) return band_index; } -/// type - conversion -// Not handle burst size + void meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ @@ -271,7 +269,7 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ entry->stats->band_stats[b]->byte_band_count += (*pkt)->buffer->size; entry->stats->band_stats[b]->packet_band_count++; if (drop){ - VLOG_ERR_RL(LOG_MODULE, &rl, "Dropping packet: rate %d", band_header->rate); + VLOG_DBG_RL(LOG_MODULE, &rl, "Dropping packet: rate %d", band_header->rate); packet_destroy(*pkt); *pkt = NULL; } @@ -279,7 +277,6 @@ meter_entry_apply(struct meter_entry *entry, struct packet **pkt){ } - /* Returns true if the meter entry has reference to the flow entry. */ static bool has_flow_ref(struct meter_entry *entry, struct flow_entry *fe) { @@ -325,34 +322,31 @@ refill_bucket(struct meter_entry *entry) for(i = 0; i < entry->config->meter_bands_num; i++) { long long int now = time_msec(); - long long int tokens = !(entry->config->flags & OFPMF_PKTPS) ? - (now - entry->stats->band_stats[i]->last_fill) * - entry->config->bands[i]->rate + entry->stats->band_stats[i]->tokens - : (now - entry->stats->band_stats[i]->last_fill) * - (entry->config->bands[i]->rate * 1000) + entry->stats->band_stats[i]->tokens; - + uint32_t rate; + uint32_t burst_size; + uint64_t tokens; + rate = entry->config->bands[i]->rate * 1000; + burst_size = entry->config->bands[i]->burst_size * 1000; + tokens = (now - entry->stats->band_stats[i]->last_fill) * + rate + entry->stats->band_stats[i]->tokens; + entry->stats->band_stats[i]->last_fill = now; if (!(entry->config->flags & OFPMF_BURST)){ if(entry->config->flags & OFPMF_KBPS && tokens >= 1){ - entry->stats->band_stats[i]->tokens = MIN(tokens, entry->config->bands[i]->rate); - entry->stats->band_stats[i]->last_fill = now; - + entry->stats->band_stats[i]->tokens = MIN(tokens, rate); } else{ if(tokens >= 1000) { - entry->stats->band_stats[i]->tokens = MIN(tokens, entry->config->bands[i]->rate * 1000); - entry->stats->band_stats[i]->last_fill = now; - + entry->stats->band_stats[i]->tokens = MIN(tokens, rate); } } } else { - if(entry->config->flags & OFPMF_KBPS && tokens >= 1 ) { - entry->stats->band_stats[i]->tokens = MIN(tokens, entry->config->bands[i]->burst_size); - + if(entry->config->flags & OFPMF_KBPS && tokens >= 1 ){ + entry->stats->band_stats[i]->tokens = MIN(tokens,burst_size); } else { if(tokens >= 1000) { - entry->stats->band_stats[i]->tokens = MIN(tokens, entry->config->bands[i]->burst_size * 1000); + entry->stats->band_stats[i]->tokens = MIN(tokens,burst_size); } } } From 8089471f75eb94bcbfcc6885d521e1407bddf661 Mon Sep 17 00:00:00 2001 From: Chris Kappler Date: Fri, 11 Apr 2014 05:37:24 -0700 Subject: [PATCH 123/191] Fixed masking logic for: masked ip range forwarding masked rule overlap detection masked rule overwrite detection --- udatapath/match_std.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 1108953b..35671dab 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -64,7 +64,7 @@ static inline bool match_mask16(uint8_t *a, uint8_t *am, uint8_t *b) { uint16_t *a1 = (uint16_t *) a; uint16_t *b1 = (uint16_t *) b; - uint16_t *mask = (uint16_t*) am; + uint16_t *mask = (uint16_t *) am; return (((*mask) & (*a1 ^ *b1)) == 0); } @@ -95,7 +95,7 @@ static inline bool match_mask32(uint8_t *a, uint8_t *am, uint8_t *b) { uint32_t *a1 = (uint32_t *) a; uint32_t *b1 = (uint32_t *) b; - uint32_t *mask = (uint32_t*) am; + uint32_t *mask = (uint32_t *) am; return (((*mask) & (*a1 ^ *b1)) == 0); } @@ -126,8 +126,8 @@ static inline bool match_mask64(uint8_t *a, uint8_t *am, uint8_t *b) { uint64_t *a1 = (uint64_t *) a; uint64_t *b1 = (uint64_t *) b; - uint64_t mask = *((uint64_t*) am); - return (((mask) & (*a1 ^ *b1)) == 0); + uint64_t *mask = (uint64_t *) am; + return (((*mask) & (*a1 ^ *b1)) == 0); } /* Returns true if two 128 bit values match */ @@ -311,7 +311,7 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ static inline bool strict_mask8(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { - return ((am[0] == bm[0]) && ((a[0] ^ b[0]) & ~am[0])) == 0; + return ((am[0] == bm[0]) && ((a[0] ^ b[0]) & am[0])) == 0; } static inline bool @@ -320,7 +320,7 @@ strict_mask16(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint16_t *b1 = (uint16_t *) b; uint16_t *mask_a = (uint16_t *) am; uint16_t *mask_b = (uint16_t *) bm; - return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & ~(*mask_a))) == 0; + return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & (*mask_a))) == 0; } static inline bool @@ -335,7 +335,7 @@ strict_mask32(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint32_t *b1 = (uint32_t *) b; uint32_t *mask_a = (uint32_t *) am; uint32_t *mask_b = (uint32_t *) bm; - return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & ~(*mask_a))) == 0; + return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & (*mask_a))) == 0; } static inline bool @@ -359,7 +359,7 @@ strict_mask64(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint64_t *b1 = (uint64_t *) b; uint64_t *mask_a = (uint64_t *) am; uint64_t *mask_b = (uint64_t *) bm; - return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & ~(*mask_a))) == 0; + return ((*mask_a == *mask_b) && ((*a1 ^ *b1) & (*mask_a))) == 0; } static inline bool @@ -708,7 +708,7 @@ match_std_nonstrict(struct ofl_match *a, struct ofl_match *b) static inline bool incompatible_8(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { - return (( ~(*am|*bm) & (*a^*b) ) != 0); + return (( (*am&*a) ^ (*bm&*b) ) != 0); } static inline bool @@ -718,7 +718,7 @@ incompatible_16(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint16_t *mask_a = (uint16_t *) am; uint16_t *mask_b = (uint16_t *) bm; - return (( ~(*mask_a|*mask_b) & (*a1^*b1) ) != 0); + return (( (*mask_a&*a1) ^ (*mask_b&*b1) ) != 0); } static inline bool @@ -728,7 +728,7 @@ incompatible_32(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint32_t *mask_a = (uint32_t *) am; uint32_t *mask_b = (uint32_t *) bm; - return (( ~(*mask_a|*mask_b) & (*a1^*b1) ) != 0); + return (( (*mask_a&*a1)^(*mask_b&*b1) ) != 0); } static inline bool @@ -744,7 +744,7 @@ incompatible_64(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { uint64_t *mask_a = (uint64_t *) am; uint64_t *mask_b = (uint64_t *) bm; - return (( ~(*mask_a|*mask_b) & (*a1^*b1) ) != 0); + return (( (*mask_a&*a1) ^ (*mask_b&*b1) ) != 0); } static inline bool @@ -762,7 +762,8 @@ incompatible_128(uint8_t *a, uint8_t *b, uint8_t *am, uint8_t *bm) { bool match_std_overlap(struct ofl_match *a, struct ofl_match *b) { - uint64_t all_mask[2] = {0, 0}; + uint64_t all_mask[2] = {~0L, ~0L}; + struct ofl_match_tlv *f_a; struct ofl_match_tlv *f_b; int header, header_m; From 3b6a7746e38ba45a7f2c142f429a04394b5f27cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Fri, 22 May 2015 11:04:30 -0300 Subject: [PATCH 124/191] Fix endianity problem after setting eth_type. This commit fixes the endianity change of the eth_type value in a set_field action. Fixes #157. --- udatapath/dp_actions.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/udatapath/dp_actions.c b/udatapath/dp_actions.c index e53ec858..f2d5737a 100644 --- a/udatapath/dp_actions.c +++ b/udatapath/dp_actions.c @@ -94,10 +94,8 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) break; } case OXM_OF_ETH_TYPE:{ - uint16_t *v = (uint16_t*) act->field->value; - *v = htons(*v); - memcpy(&pkt->handle_std->proto->eth->eth_type, - v, OXM_LENGTH(act->field->header)); + uint16_t v = *((uint16_t*) act->field->value); + pkt->handle_std->proto->eth->eth_type = htons(v); break; } case OXM_OF_VLAN_VID:{ @@ -105,8 +103,7 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) /* VLAN existence is no guaranteed by match prerquisite*/ if(vlan != NULL){ uint16_t v = (*(uint16_t*)act->field->value); - vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) - | (v & VLAN_VID_MASK)); + vlan->vlan_tci = htons((ntohs(vlan->vlan_tci) & ~VLAN_VID_MASK) | (v & VLAN_VID_MASK)); } break; } @@ -209,29 +206,28 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) struct tcp_header *tcp = pkt->handle_std->proto->tcp; uint16_t v = htons(*(uint16_t*) act->field->value); tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_src, v); - memcpy(&tcp->tcp_src, &v, OXM_LENGTH(act->field->header)); + tcp->tcp_src = v; break; } case OXM_OF_TCP_DST:{ struct tcp_header *tcp = pkt->handle_std->proto->tcp; uint16_t v = htons(*(uint16_t*) act->field->value); tcp->tcp_csum = recalc_csum16(tcp->tcp_csum, tcp->tcp_dst, v); - memcpy(&tcp->tcp_dst, &v, OXM_LENGTH(act->field->header)); + tcp->tcp_dst = v; break; } case OXM_OF_UDP_SRC:{ struct udp_header *udp = pkt->handle_std->proto->udp; uint16_t v = htons(*(uint16_t*) act->field->value); udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_src, v); - memcpy(&udp->udp_src, &v, OXM_LENGTH(act->field->header)); - + udp->udp_src = v; break; } case OXM_OF_UDP_DST:{ struct udp_header *udp = pkt->handle_std->proto->udp; uint16_t v = htons(*(uint16_t*) act->field->value); udp->udp_csum = recalc_csum16(udp->udp_csum, udp->udp_dst, v); - memcpy(&udp->udp_dst, &v, OXM_LENGTH(act->field->header)); + udp->udp_dst = v; break; } /*TODO recalculate SCTP checksum*/ @@ -241,7 +237,7 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) size_t len = ((uint8_t*) ofpbuf_tail(pkt->handle_std->pkt->buffer)) - (uint8_t *) sctp; uint16_t v = htons(*(uint16_t*) act->field->value); sctp->sctp_csum = 0; - memcpy(&sctp->sctp_src, &v, OXM_LENGTH(act->field->header)); + sctp->sctp_src = v; crc = crc_init(); crc = crc_update(crc, (unsigned char*)sctp, len); crc = crc_finalize(crc); @@ -254,7 +250,7 @@ set_field(struct packet *pkt, struct ofl_action_set_field *act ) size_t len = ((uint8_t*) ofpbuf_tail(pkt->handle_std->pkt->buffer)) - (uint8_t *) sctp; uint16_t v = htons(*(uint16_t*) act->field->value); sctp->sctp_csum = 0; - memcpy(&sctp->sctp_dst, &v, OXM_LENGTH(act->field->header)); + sctp->sctp_dst = v; crc = crc_init(); crc = crc_update(crc, (unsigned char*)sctp, len); crc = crc_finalize(crc); @@ -1227,3 +1223,4 @@ dp_actions_check_set_field_req(struct ofl_msg_flow_mod *msg, size_t actions_num, } return 0; } + From 9227dcc9b88f4a5e33d8ec1469ac176f710d98df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 11 Jun 2015 21:51:05 -0300 Subject: [PATCH 125/191] Implement port up/down detection. This commit implements port up/down detection through a netlink socket that listens for RTMGRP_LINK messages. --- lib/netdev.c | 60 ++++++++++++++++++++++++++++++++++++++++++-- lib/netdev.h | 9 +++++++ udatapath/dp_ports.c | 15 ++++++++--- 3 files changed, 78 insertions(+), 6 deletions(-) diff --git a/lib/netdev.c b/lib/netdev.c index 5352e730..b9d5f220 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -71,6 +71,7 @@ #include #include #include +#include #include #include @@ -96,7 +97,6 @@ #endif #include -#include #include #include #include @@ -141,6 +141,8 @@ struct netdev { int tap_fd; /* TAP character device, if any, otherwise the * network device. */ + int netlink_fd; + /* one socket per queue.These are valid only for ordinary network devices*/ int queue_fd[NETDEV_MAX_QUEUES + 1]; uint16_t num_queues; @@ -721,7 +723,9 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, struct netdev **netdev_) { int netdev_fd; + int netlink_fd; struct sockaddr_ll sll; + struct sockaddr_nl snl; struct ifreq ifr; unsigned int ifindex; uint8_t etheraddr[ETH_ADDR_LEN]; @@ -736,6 +740,18 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, init_netdev(); *netdev_ = NULL; + netlink_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + + if (netlink_fd < 0) { + return errno; + } + + /* Set non-blocking mode. */ + error = set_nonblocking(netlink_fd); + if (error) { + goto error_already_set; + } + /* Create raw socket. */ netdev_fd = socket(PF_PACKET, SOCK_RAW, htons(ethertype == NETDEV_ETH_TYPE_NONE ? 0 @@ -759,6 +775,14 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, goto error_already_set; } + memset (&snl,0,sizeof(snl)); + snl.nl_family = AF_NETLINK; + snl.nl_groups = RTMGRP_LINK; + + if (bind(netlink_fd, (struct sockaddr *)&snl, sizeof(snl)) < 0){ + VLOG_ERR(LOG_MODULE, "netlink bind to %s failed: %s", name, strerror(errno)); + goto error; + } /* Get ethernet device index. */ strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); if (ioctl(netdev_fd, SIOCGIFINDEX, &ifr) < 0) { @@ -826,6 +850,7 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, netdev->txqlen = txqlen; netdev->hwaddr_family = hwaddr_family; netdev->netdev_fd = netdev_fd; + netdev->netlink_fd = netlink_fd; netdev->tap_fd = tap_fd < 0 ? netdev_fd : tap_fd; netdev->queue_fd[0] = netdev->tap_fd; memcpy(netdev->etheraddr, etheraddr, sizeof etheraddr); @@ -903,6 +928,38 @@ pad_to_minimum_length(struct ofpbuf *buffer) } } +int +netdev_link_state(struct netdev *netdev) +{ + int len; + char buff[4096]; + struct nlmsghdr *nlm; + struct ifinfomsg *ifa; + enum netdev_flags flags; + nlm = (struct nlmsghdr *)buff; + do + { + len = recv (netdev->netlink_fd,nlm,4096,0); + for (;(NLMSG_OK (nlm, len)) && (nlm->nlmsg_type != NLMSG_DONE); nlm = NLMSG_NEXT(nlm, len)) + { + if (nlm->nlmsg_type != RTM_NEWLINK) + continue; + ifa = (struct ifinfomsg *) NLMSG_DATA (nlm); + if (ifa->ifi_flags & IFF_UP){ + netdev_nodev_get_flags(netdev->name, &flags); + netdev_set_flags(netdev, flags, false); + return NETDEV_LINK_UP; + } + else { + netdev_nodev_get_flags(netdev->name, &flags); + netdev_set_flags(netdev, flags, false); + return NETDEV_LINK_DOWN; + } + } + } while (len < 0 && errno == EINTR); + return NETDEV_LINK_NO_CHANGE; +} + /* Attempts to receive a packet from 'netdev' into 'buffer', which the caller * must have initialized with sufficient room for the packet. The space * required to receive any packet is ETH_HEADER_LEN bytes, plus VLAN_HEADER_LEN @@ -918,7 +975,6 @@ pad_to_minimum_length(struct ofpbuf *buffer) int netdev_recv(struct netdev *netdev, struct ofpbuf *buffer, size_t max_mtu) { - #ifdef HAVE_PACKET_AUXDATA /* Code from libpcap to reconstruct VLAN header */ struct iovec iov; diff --git a/lib/netdev.h b/lib/netdev.h index b55c6c45..342b0ab4 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -68,8 +68,16 @@ enum netdev_pseudo_ethertype { NETDEV_ETH_TYPE_802_2 /* Receive all IEEE 802.2 frames. */ }; +enum netdev_link_state { + NETDEV_LINK_UP = 1, + NETDEV_LINK_DOWN = 2, + NETDEV_LINK_NO_CHANGE = 3 +}; + #define NETDEV_MAX_QUEUES 8 + + struct netdev; int netdev_open(const char *name, int ethertype, struct netdev **); @@ -78,6 +86,7 @@ void netdev_close(struct netdev *); int netdev_recv(struct netdev *, struct ofpbuf *, size_t); void netdev_recv_wait(struct netdev *); +int netdev_link_state(struct netdev *netdev); int netdev_drain(struct netdev *); int netdev_send(struct netdev *, const struct ofpbuf *, uint16_t class_id); void netdev_send_wait(struct netdev *); diff --git a/udatapath/dp_ports.c b/udatapath/dp_ports.c index ea915ab1..39ab98f2 100644 --- a/udatapath/dp_ports.c +++ b/udatapath/dp_ports.c @@ -260,6 +260,16 @@ dp_ports_run(struct datapath *dp) { LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { int error; + /* Check for interface state change */ + enum netdev_link_state link_state = netdev_link_state(p->netdev); + if (link_state == NETDEV_LINK_UP){ + p->conf->state &= ~OFPPS_LINK_DOWN; + dp_port_live_update(p); + } + else if (link_state == NETDEV_LINK_DOWN){ + p->conf->state |= OFPPS_LINK_DOWN; + dp_port_live_update(p); + } if (IS_HW_PORT(p)) { continue; @@ -279,9 +289,6 @@ dp_ports_run(struct datapath *dp) { process_buffer(dp, p, buffer); buffer = NULL; } else if (error != EAGAIN) { - if(error == ENETDOWN){ - p->conf->state = OFPPS_LINK_DOWN; - } VLOG_ERR_RL(LOG_MODULE, &rl, "error receiving data from %s: %s", netdev_get_name(p->netdev), strerror(error)); } @@ -682,7 +689,7 @@ dp_ports_handle_port_mod(struct datapath *dp, struct ofl_msg_port_mod *msg, if (msg->mask) { p->conf->config &= ~msg->mask; p->conf->config |= msg->config & msg->mask; - dp_port_live_update(p); + dp_port_live_update(p); } /*Notify all controllers that the port status has changed*/ From 37a17cf59be417e6cd08279a5d34fd39043e5ec9 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Thu, 18 Jun 2015 15:30:27 -0300 Subject: [PATCH 126/191] Fix queue id check when looking up or adding new queues. --- udatapath/dp_ports.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/udatapath/dp_ports.c b/udatapath/dp_ports.c index ea915ab1..cd026991 100644 --- a/udatapath/dp_ports.c +++ b/udatapath/dp_ports.c @@ -555,7 +555,7 @@ dp_ports_lookup_queue(struct sw_port *p, uint32_t queue_id) { struct sw_queue *q; - if (queue_id <= p->max_queues) { + if (queue_id < p->max_queues) { q = &(p->queues[queue_id]); if (q->port != NULL) { @@ -988,7 +988,7 @@ static int port_add_queue(struct sw_port *p, uint32_t queue_id, struct ofl_queue_prop_min_rate * mr) { - if (queue_id > p->max_queues) { + if (queue_id >= p->max_queues) { return EXFULL; } From 8d3df820f7487f541b3f5862081a939aad76d8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 2 Jul 2015 21:07:38 -0300 Subject: [PATCH 127/191] Fix port up/down detection. Check if the port index from the netlink message is the same from the netdev port. It is necessary because other ports might be running in the dp_ports_run loop. --- lib/netdev.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/netdev.c b/lib/netdev.c index b9d5f220..4055889e 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -945,16 +945,18 @@ netdev_link_state(struct netdev *netdev) if (nlm->nlmsg_type != RTM_NEWLINK) continue; ifa = (struct ifinfomsg *) NLMSG_DATA (nlm); - if (ifa->ifi_flags & IFF_UP){ - netdev_nodev_get_flags(netdev->name, &flags); - netdev_set_flags(netdev, flags, false); - return NETDEV_LINK_UP; - } - else { - netdev_nodev_get_flags(netdev->name, &flags); - netdev_set_flags(netdev, flags, false); - return NETDEV_LINK_DOWN; - } + if (ifa->ifi_index == netdev->ifindex){ + if (ifa->ifi_flags & IFF_UP){ + netdev_nodev_get_flags(netdev->name, &flags); + netdev_set_flags(netdev, flags, false); + return NETDEV_LINK_UP; + } + else { + netdev_nodev_get_flags(netdev->name, &flags); + netdev_set_flags(netdev, flags, false); + return NETDEV_LINK_DOWN; + } + } } } while (len < 0 && errno == EINTR); return NETDEV_LINK_NO_CHANGE; From 75ee6744112163341fc230e8675b0aa844aa67e4 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Tue, 15 Sep 2015 16:01:35 -0300 Subject: [PATCH 128/191] Fix small error when refilling meter band buckets. This commit fixes the calculation of how many new tokens we are supposed to add to the meter band bucket, now considering that the elapsed interval can be different of 1000 msec (in fact, the current defaul value is 100ms). --- udatapath/meter_entry.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/udatapath/meter_entry.c b/udatapath/meter_entry.c index 5820c13b..6da82b55 100644 --- a/udatapath/meter_entry.c +++ b/udatapath/meter_entry.c @@ -318,17 +318,17 @@ meter_entry_del_flow_ref(struct meter_entry *entry, struct flow_entry *fe) { void refill_bucket(struct meter_entry *entry) { - size_t i; + long long int now = time_msec(); + size_t i; for(i = 0; i < entry->config->meter_bands_num; i++) { - long long int now = time_msec(); uint32_t rate; uint32_t burst_size; uint64_t tokens; + long long int elapsed_msec = now - entry->stats->band_stats[i]->last_fill; rate = entry->config->bands[i]->rate * 1000; burst_size = entry->config->bands[i]->burst_size * 1000; - tokens = (now - entry->stats->band_stats[i]->last_fill) * - rate + entry->stats->band_stats[i]->tokens; + tokens = ((rate * elapsed_msec) / 1000) + entry->stats->band_stats[i]->tokens; entry->stats->band_stats[i]->last_fill = now; if (!(entry->config->flags & OFPMF_BURST)){ if(entry->config->flags & OFPMF_KBPS && tokens >= 1){ From e6f51ba53b05a39651b210915f23cbd5a8d634e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 00:27:41 +0000 Subject: [PATCH 129/191] Update openflow.h to OpenFlow 1.3.5 This commit updates the OpenFlow header with the most recent changes to OpenFlow 1.3. As a result all the OXM field definitions were moved from oxm-match.h to openflow.h. Some files required changes due to changes to some flags ans struct names. --- include/openflow/openflow.h | 3242 +++++++++++++++++++++-------------- oflib/ofl-messages-pack.c | 6 +- oflib/ofl-messages-unpack.c | 8 +- oflib/ofl-structs-pack.c | 2 - oflib/ofl-structs-print.c | 12 +- oflib/oxm-match.c | 2 +- oflib/oxm-match.h | 224 +-- udatapath/flow_table.c | 2 +- udatapath/pipeline.c | 11 +- 9 files changed, 1945 insertions(+), 1564 deletions(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index e72f2801..2fb42c70 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -1,3 +1,37 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * Copyright (c) 2011, 2012 Open Networking Foundation + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks 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 @@ -8,16 +42,18 @@ #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; })] + 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 @@ -25,671 +61,1146 @@ #endif /* Version number: - * Non-experimental versions released: 0x01 - * Experimental versions released: 0x81 -- 0x99 + * OpenFlow versions released: 0x01 = 1.0 ; 0x02 = 1.1 ; 0x03 = 1.2 + * 0x04 = 1.3 */ -/* The most significant bit being set in the version field indicates an - * experimental OpenFlow version. +/* The most significant bit in the version field is reserved and must + * be set to zero. */ - #define OFP_VERSION 0x04 +#define PIPELINE_TABLES 64 #define OFP_MAX_TABLE_NAME_LEN 32 #define OFP_MAX_PORT_NAME_LEN 16 +<<<<<<< HEAD #define OFP_TCP_PORT 6653 #define OFP_SSL_PORT 6653 +======= + +/* Official IANA registered port for OpenFlow. */ +#define OFP_TCP_PORT 6653 +#define OFP_SSL_PORT 6653 + +>>>>>>> e309316... Update openflow.h to OpenFlow 1.3.5 #define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */ -/* Number of tables in the pipeline */ -#define PIPELINE_TABLES 64 -/* 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 - total_len facilitate pairing. */ +/* Port numbering. Ports are numbered starting from 1. */ +enum ofp_port_no { + /* Maximum number of physical and logical switch ports. */ + OFPP_MAX = 0xffffff00, + + /* Reserved OpenFlow Port (fake output "ports"). */ + OFPP_IN_PORT = 0xfffffff8, /* Send the packet out the input port. This + reserved port must be explicitly used + in order to send back out of the input + port. */ + OFPP_TABLE = 0xfffffff9, /* Submit the packet to the first flow table + NB: This destination port can only be + used in packet-out messages. */ + OFPP_NORMAL = 0xfffffffa, /* Forward using non-OpenFlow pipeline. */ + OFPP_FLOOD = 0xfffffffb, /* Flood using non-OpenFlow pipeline. */ + OFPP_ALL = 0xfffffffc, /* All standard ports except input port. */ + OFPP_CONTROLLER = 0xfffffffd, /* Send to controller. */ + OFPP_LOCAL = 0xfffffffe, /* Local openflow "port". */ + OFPP_ANY = 0xffffffff /* Special value used in some requests when + no port is specified (i.e. wildcarded). */ }; -OFP_ASSERT(sizeof(struct ofp_header) == 8); enum ofp_type { - /* Immutable messages. */ - OFPT_HELLO = 0, /* Symmetric message */ - OFPT_ERROR = 1, /* Symmetric message */ - OFPT_ECHO_REQUEST = 2, /* Symmetric message */ - OFPT_ECHO_REPLY = 3, /* Symmetric message */ - OFPT_EXPERIMENTER = 4, /* Symmetric message */ + /* Immutable messages. */ + OFPT_HELLO = 0, /* Symmetric message */ + OFPT_ERROR = 1, /* Symmetric message */ + OFPT_ECHO_REQUEST = 2, /* Symmetric message */ + OFPT_ECHO_REPLY = 3, /* Symmetric message */ + OFPT_EXPERIMENTER = 4, /* Symmetric message */ + /* Switch configuration messages. */ - OFPT_FEATURES_REQUEST = 5, /* Controller/switch message */ - OFPT_FEATURES_REPLY = 6, /* Controller/switch message */ - OFPT_GET_CONFIG_REQUEST = 7, /* Controller/switch message */ - OFPT_GET_CONFIG_REPLY = 8, /* Controller/switch message */ - OFPT_SET_CONFIG = 9, /* Controller/switch message */ + OFPT_FEATURES_REQUEST = 5, /* Controller/switch message */ + OFPT_FEATURES_REPLY = 6, /* Controller/switch message */ + OFPT_GET_CONFIG_REQUEST = 7, /* Controller/switch message */ + OFPT_GET_CONFIG_REPLY = 8, /* Controller/switch message */ + OFPT_SET_CONFIG = 9, /* Controller/switch message */ + /* Asynchronous messages. */ - OFPT_PACKET_IN = 10, /* Async message */ - OFPT_FLOW_REMOVED = 11, /* Async message */ - OFPT_PORT_STATUS = 12, /* Async message */ + OFPT_PACKET_IN = 10, /* Async message */ + OFPT_FLOW_REMOVED = 11, /* Async message */ + OFPT_PORT_STATUS = 12, /* Async message */ + /* Controller command messages. */ - OFPT_PACKET_OUT = 13, /* Controller/switch message */ - OFPT_FLOW_MOD = 14, /* Controller/switch message */ - OFPT_GROUP_MOD = 15, /* Controller/switch message */ - OFPT_PORT_MOD = 16, /* Controller/switch message */ - OFPT_TABLE_MOD = 17, /* Controller/switch message */ - /* Statistics messages. */ - OFPT_MULTIPART_REQUEST = 18, /* Controller/switch message */ - OFPT_MULTIPART_REPLY = 19, /* Controller/switch message */ + OFPT_PACKET_OUT = 13, /* Controller/switch message */ + OFPT_FLOW_MOD = 14, /* Controller/switch message */ + OFPT_GROUP_MOD = 15, /* Controller/switch message */ + OFPT_PORT_MOD = 16, /* Controller/switch message */ + OFPT_TABLE_MOD = 17, /* Controller/switch message */ + + /* Multipart messages. */ + OFPT_MULTIPART_REQUEST = 18, /* Controller/switch message */ + OFPT_MULTIPART_REPLY = 19, /* Controller/switch message */ + /* Barrier messages. */ - OFPT_BARRIER_REQUEST = 20, /* Controller/switch message */ - OFPT_BARRIER_REPLY = 21, /* Controller/switch message */ + OFPT_BARRIER_REQUEST = 20, /* Controller/switch message */ + OFPT_BARRIER_REPLY = 21, /* Controller/switch message */ + /* Queue Configuration messages. */ - OFPT_QUEUE_GET_CONFIG_REQUEST = 22, /* Controller/switch message */ - OFPT_QUEUE_GET_CONFIG_REPLY = 23, /* Controller/switch message */ + OFPT_QUEUE_GET_CONFIG_REQUEST = 22, /* Controller/switch message */ + OFPT_QUEUE_GET_CONFIG_REPLY = 23, /* Controller/switch message */ + /* Controller role change request messages. */ - OFPT_ROLE_REQUEST = 24, /* Controller/switch message */ - OFPT_ROLE_REPLY = 25, /* Controller/switch message */ - /* Asynchronous message configuration */ - OFPT_GET_ASYNC_REQUEST = 26, /* Controller/switch message */ - OFPT_GET_ASYNC_REPLY = 27, /* Controller/switch message */ - OFPT_SET_ASYNC = 28, /* Controller/switch message */ + OFPT_ROLE_REQUEST = 24, /* Controller/switch message */ + OFPT_ROLE_REPLY = 25, /* Controller/switch message */ + + /* Asynchronous message configuration. */ + OFPT_GET_ASYNC_REQUEST = 26, /* Controller/switch message */ + OFPT_GET_ASYNC_REPLY = 27, /* Controller/switch message */ + OFPT_SET_ASYNC = 28, /* Controller/switch message */ + /* Meters and rate limiters configuration messages. */ - OFPT_METER_MOD = 29, /* Controller/switch message */ + OFPT_METER_MOD = 29, /* Controller/switch message */ }; -/* OFPT_HELLO. This message has an empty body, but implementations must - * ignore any data included in the body, to allow for future extensions. */ +/* 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); + +/* Hello elements types. + */ +enum ofp_hello_elem_type { + OFPHET_VERSIONBITMAP = 1, /* Bitmap of version supported. */ +}; + +/* Common header for all Hello Elements */ +struct ofp_hello_elem_header { + uint16_t type; /* One of OFPHET_*. */ + uint16_t length; /* Length in bytes of the element, + including this header, excluding padding. */ +}; +OFP_ASSERT(sizeof(struct ofp_hello_elem_header) == 4); + +/* Version bitmap Hello Element */ +struct ofp_hello_elem_versionbitmap { + uint16_t type; /* OFPHET_VERSIONBITMAP. */ + uint16_t length; /* Length in bytes of this element, + including this header, excluding padding. */ + /* Followed by: + * - Exactly (length - 4) bytes containing the bitmaps, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + uint32_t bitmaps[0]; /* List of bitmaps - supported versions */ +}; +OFP_ASSERT(sizeof(struct ofp_hello_elem_versionbitmap) == 4); + +/* OFPT_HELLO. This message includes zero or more hello elements having + * variable size. Unknown elements types must be ignored/skipped, to allow + * for future extensions. */ struct ofp_hello { struct ofp_header header; + + /* Hello element list */ + struct ofp_hello_elem_header elements[0]; /* List of elements - 0 or more */ }; +OFP_ASSERT(sizeof(struct ofp_hello) == 8); #define OFP_DEFAULT_MISS_SEND_LEN 128 -/******** Common Structures **********************/ +enum ofp_config_flags { + /* Handling of IP fragments. */ + OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */ + OFPC_FRAG_DROP = 1 << 0, /* Drop fragments. */ + OFPC_FRAG_REASM = 1 << 1, /* Reassemble (only if OFPC_IP_REASM set). */ + OFPC_FRAG_MASK = 3, /* Bitmask of flags dealing with frag. */ +}; +/* Switch configuration. */ +struct ofp_switch_config { + struct ofp_header header; + uint16_t flags; /* Bitmap of OFPC_* flags. */ + uint16_t miss_send_len; /* Max bytes of packet that datapath + should send to the controller. See + ofp_controller_max_len for valid values. + */ +}; +OFP_ASSERT(sizeof(struct ofp_switch_config) == 12); -/* Description of a port */ -struct ofp_port { - uint32_t port_no; - uint8_t pad[4]; - uint8_t hw_addr[OFP_ETH_ALEN]; - uint8_t pad2[2]; /* Align to 64 bits. */ - 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. */ - uint32_t curr_speed; /* Current port bitrate in kbps. */ - uint32_t max_speed; /* Max port bitrate in kbps */ +/* Flags to configure the table. Reserved for future use. */ +enum ofp_table_config { + OFPTC_DEPRECATED_MASK = 3, /* Deprecated bits */ }; -OFP_ASSERT(sizeof(struct ofp_port) == 64); -/* Flags to indicate behavior of the physical port. These flags are -* used in ofp_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_RECV = 1 << 2, /* Drop all packets received by port. */ - OFPPC_NO_FWD = 1 << 5, /* Drop packets forwarded to port. */ - OFPPC_NO_PACKET_IN = 1 << 6 /* Do not send packet-in msgs for port. */ +/* Table numbering. Tables can use any number up to OFPT_MAX. */ +enum ofp_table { + /* Last usable table number. */ + OFPTT_MAX = 0xfe, + + /* Fake tables. */ + OFPTT_ALL = 0xff /* Wildcard table used for table config, + flow stats and flow deletes. */ }; -/* 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. */ - OFPPS_BLOCKED = 1 << 1, /* Port is blocked */ - OFPPS_LIVE = 1 << 2, /* Live for Fast Failover Group. */ + +/* Configure/Modify behavior of a flow table */ +struct ofp_table_mod { + struct ofp_header header; + uint8_t table_id; /* ID of the table, OFPTT_ALL indicates all tables */ + uint8_t pad[3]; /* Pad to 32 bits */ + uint32_t config; /* Bitmap of OFPTC_* flags */ }; +OFP_ASSERT(sizeof(struct ofp_table_mod) == 16); -/* Port numbering. Ports are numbered starting from 1. */ -enum ofp_port_no { - /* Maximum number of physical and logical switch ports. */ - OFPP_MAX = 0xffffff00, - /* Reserved OpenFlow Port (fake output "ports"). */ - OFPP_IN_PORT = 0xfffffff8, /* Send the packet out the input port. This - reserved port must be explicitly used - in order to send back out of the input - port. */ - OFPP_TABLE = 0xfffffff9, /* Submit the packet to the first flow table - NB: This destination port can only be - used in packet-out messages. */ - OFPP_NORMAL = 0xfffffffa, /* Process with normal L2/L3 switching. */ - OFPP_FLOOD = 0xfffffffb, /* All physical ports in VLAN, except input - port and those blocked or link down. */ - OFPP_ALL = 0xfffffffc, /* All physical ports except input port. */ - OFPP_CONTROLLER = 0xfffffffd, /* Send to controller. */ - OFPP_LOCAL = 0xfffffffe, /* Local openflow "port". */ - OFPP_ANY = 0xffffffff /* Wildcard port used only for flow mod - (delete) and flow stats requests. Selects - all flows regardless of output port - (including flows with no output port). */ +/* 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_GROUP_STATS = 1 << 3, /* Group statistics. */ + OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ + OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */ + OFPC_PORT_BLOCKED = 1 << 8 /* Switch will block looping ports. */ +}; + +/* Flags to indicate behavior of the physical port. These flags are + * used in ofp_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_RECV = 1 << 2, /* Drop all packets received by port. */ + 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. */ + OFPPS_BLOCKED = 1 << 1, /* Port is blocked */ + OFPPS_LIVE = 1 << 2, /* Live for Fast Failover Group. */ }; /* Features of 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_40GB_FD = 1 << 7, /* 40 Gb full-duplex rate support. */ - OFPPF_100GB_FD = 1 << 8, /* 100 Gb full-duplex rate support. */ - OFPPF_1TB_FD = 1 << 9, /* 1 Tb full-duplex rate support. */ - OFPPF_OTHER = 1 << 10, /* Other rate, not in the list. */ - OFPPF_COPPER = 1 << 11, /* Copper medium. */ - OFPPF_FIBER = 1 << 12, /* Fiber medium. */ - OFPPF_AUTONEG = 1 << 13, /* Auto-negotiation. */ - OFPPF_PAUSE = 1 << 14, /* Pause. */ + 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_40GB_FD = 1 << 7, /* 40 Gb full-duplex rate support. */ + OFPPF_100GB_FD = 1 << 8, /* 100 Gb full-duplex rate support. */ + OFPPF_1TB_FD = 1 << 9, /* 1 Tb full-duplex rate support. */ + OFPPF_OTHER = 1 << 10, /* Other rate, not in the list. */ + + OFPPF_COPPER = 1 << 11, /* Copper medium. */ + OFPPF_FIBER = 1 << 12, /* Fiber medium. */ + OFPPF_AUTONEG = 1 << 13, /* Auto-negotiation. */ + OFPPF_PAUSE = 1 << 14, /* Pause. */ OFPPF_PAUSE_ASYM = 1 << 15 /* Asymmetric pause. */ }; -/* 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); +/* Description of a port */ +struct ofp_port { + uint32_t port_no; + uint8_t pad[4]; + uint8_t hw_addr[OFP_ETH_ALEN]; + uint8_t pad2[2]; /* Align to 64 bits. */ + char name[OFP_MAX_PORT_NAME_LEN]; /* Null-terminated */ -/* Full description for a queue. */ -struct ofp_packet_queue { - uint32_t queue_id; /* id for the specific queue. */ - uint32_t port; /* Port this queue is attached to. */ - uint16_t len; /* Length in bytes of this queue desc. */ - uint8_t pad[6]; /* 64-bit alignment. */ - struct ofp_queue_prop_header properties[0]; /* List of properties. */ + 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. */ + + uint32_t curr_speed; /* Current port bitrate in kbps. */ + uint32_t max_speed; /* Max port bitrate in kbps */ }; -OFP_ASSERT(sizeof(struct ofp_packet_queue) == 16); +OFP_ASSERT(sizeof(struct ofp_port) == 64); -/* All ones is used to indicate all queues in a port (for stats retrieval). */ -#define OFPQ_ALL 0xffffffff +/* 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. */ -/* Min rate > 1000 means not configured. */ -#define OFPQ_MIN_RATE_UNCFG 0xffff + uint32_t n_buffers; /* Max packets buffered at once. */ + uint8_t n_tables; /* Number of tables supported by datapath. */ + uint8_t auxiliary_id; /* Identify auxiliary connections */ + uint8_t pad[2]; /* Align to 64-bits. */ -enum ofp_queue_properties { - OFPQT_MIN_RATE = 1, /* Minimum datarate guaranteed. */ - OFPQT_MAX_RATE = 2, /* Maximum datarate. */ - OFPQT_EXPERIMENTER = 0xffff /* Experimenter defined property. */ + /* Features. */ + uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */ + uint32_t reserved; }; +OFP_ASSERT(sizeof(struct ofp_switch_features) == 32); -/* 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 */ +/* What changed about the physical port */ +enum ofp_port_reason { + OFPPR_ADD = 0, /* The port was added. */ + OFPPR_DELETE = 1, /* The port was removed. */ + OFPPR_MODIFY = 2, /* Some attribute of the port has changed. */ }; -OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16); -/* Max-Rate queue property description. */ -struct ofp_queue_prop_max_rate { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MAX, len: 16. */ - uint16_t rate; /* In 1/10 of a percent; >1000 -> disabled. */ - uint8_t pad[6]; /* 64-bit alignment */ +/* 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_port desc; }; -OFP_ASSERT(sizeof(struct ofp_queue_prop_max_rate) == 16); +OFP_ASSERT(sizeof(struct ofp_port_status) == 80); -/* Experimenter queue property description. */ -struct ofp_queue_prop_experimenter { - struct ofp_queue_prop_header prop_header; /* prop: OFPQT_EXPERIMENTER, len: 16. */ - uint32_t experimenter; /* Experimenter ID which takes the same - form as in struct ofp_experimenter_header. */ - uint8_t pad[4]; /* 64-bit alignment */ - uint8_t data[0]; /* Experimenter defined data. */ +/* Modify behavior of the physical port */ +struct ofp_port_mod { + struct ofp_header header; + uint32_t port_no; + uint8_t pad[4]; + 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_port struct. */ + uint8_t pad2[2]; /* Pad to 64 bits. */ + uint32_t config; /* Bitmap of OFPPC_* flags. */ + uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */ + + uint32_t advertise; /* Bitmap of OFPPF_*. Zero all bits to prevent + any action taking place. */ + uint8_t pad3[4]; /* Pad to 64 bits. */ +}; +OFP_ASSERT(sizeof(struct ofp_port_mod) == 40); + +/* ## -------------------------- ## */ +/* ## OpenFlow Extensible Match. ## */ +/* ## -------------------------- ## */ + +/* The match type indicates the match structure (set of fields that compose the + * match) in use. The match type is placed in the type field at the beginning + * of all match structures. The "OpenFlow Extensible Match" type corresponds + * to OXM TLV format described below and must be supported by all OpenFlow + * switches. Extensions that define other match types may be published on the + * ONF wiki. Support for extensions is optional. + */ +enum ofp_match_type { + OFPMT_STANDARD = 0, /* Deprecated. */ + OFPMT_OXM = 1, /* OpenFlow Extensible Match */ }; -OFP_ASSERT(sizeof(struct ofp_queue_prop_experimenter) == 16); /* Fields to match against flows */ struct ofp_match { - uint16_t type; /* One of OFPMT_* */ - uint16_t length; /* Length of ofp_match (excluding padding) */ - /* Followed by: - * -Exactly (length - 4) (possibly 0) bytes containing OXM TLVs,then - * -Exactly ((length+7)/8*8-length)(between 0 and 7) bytes of - * all-zerobytes - * In summary, ofp_match is padded as needed, to make its overall size - * a multiple of 8, to preserve alignement in structures using it. - */ - uint8_t oxm_fields[4]; /* OXMs start here - Make compiler happy */ + uint16_t type; /* One of OFPMT_* */ + uint16_t length; /* Length of ofp_match (excluding padding) */ + /* Followed by: + * - Exactly (length - 4) (possibly 0) bytes containing OXM TLVs, then + * - Exactly ((length + 7)/8*8 - length) (between 0 and 7) bytes of + * all-zero bytes + * In summary, ofp_match is padded as needed, to make its overall size + * a multiple of 8, to preserve alignment in structures using it. + */ + uint8_t oxm_fields[0]; /* 0 or more OXM match fields */ + uint8_t pad[4]; /* Zero bytes - see above for sizing */ }; OFP_ASSERT(sizeof(struct ofp_match) == 8); -/* The match type indicates the match structure (set of fields that compose the -* match) in use. The match type is placed in the type field at the beginning -* of all match structures. The "OpenFlow Extensible Match" type corresponds -* to OXM TLV format described below and must be supported by all OpenFlow -* switches. Extensions that define other match types may be published on the -* ONF wiki. Support for extensions is optional. -*/ -enum ofp_match_type { - OFPMT_STANDARD = 0, /* Deprecated. */ - OFPMT_OXM = 1, /* OpenFlow Extensible Match */ -}; +/* Components of a OXM TLV header. + * Those macros are not valid for the experimenter class, macros for the + * experimenter class will depend on the experimenter header used. */ +#define OXM_HEADER__(CLASS, FIELD, HASMASK, LENGTH) \ + (((CLASS) << 16) | ((FIELD) << 9) | ((HASMASK) << 8) | (LENGTH)) +#define OXM_HEADER(CLASS, FIELD, LENGTH) \ + OXM_HEADER__(CLASS, FIELD, 0, LENGTH) +#define OXM_HEADER_W(CLASS, FIELD, LENGTH) \ + OXM_HEADER__(CLASS, FIELD, 1, (LENGTH) * 2) +#define OXM_CLASS(HEADER) ((HEADER) >> 16) +#define OXM_FIELD(HEADER) (((HEADER) >> 9) & 0x7f) +#define OXM_TYPE(HEADER) (((HEADER) >> 9) & 0x7fffff) +#define OXM_HASMASK(HEADER) (((HEADER) >> 8) & 1) +#define OXM_LENGTH(HEADER) ((HEADER) & 0xff) + +#define OXM_MAKE_WILD_HEADER(HEADER) \ + OXM_HEADER_W(OXM_CLASS(HEADER), OXM_FIELD(HEADER), OXM_LENGTH(HEADER)) /* OXM Class IDs. -* The high order bit differentiate reserved classes from member classes. -* Classes 0x0000 to 0x7FFF are member classes, allocated by ONF. -* Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation. -*/ + * The high order bit differentiate reserved classes from member classes. + * Classes 0x0000 to 0x7FFF are member classes, allocated by ONF. + * Classes 0x8000 to 0xFFFE are reserved classes, reserved for standardisation. + */ enum ofp_oxm_class { - OFPXMC_NXM_0 = 0x0000, /* Backward compatibility with NXM */ - OFPXMC_NXM_1 = 0x0001, /* Backward compatibility with NXM */ - OFPXMC_OPENFLOW_BASIC = 0x8000, /* Basic class for OpenFlow */ - OFPXMC_EXPERIMENTER = 0xFFFF, /* Experimenter class */ + OFPXMC_NXM_0 = 0x0000, /* Backward compatibility with NXM */ + OFPXMC_NXM_1 = 0x0001, /* Backward compatibility with NXM */ + OFPXMC_OPENFLOW_BASIC = 0x8000, /* Basic class for OpenFlow */ + OFPXMC_EXPERIMENTER = 0xFFFF, /* Experimenter class */ }; /* OXM Flow match field types for OpenFlow basic class. */ enum oxm_ofb_match_fields { - OFPXMT_OFB_IN_PORT = 0, /* Switch input port. */ - OFPXMT_OFB_IN_PHY_PORT = 1, /* Switch physical input port. */ - OFPXMT_OFB_METADATA = 2, /* Metadata passed between tables. */ - OFPXMT_OFB_ETH_DST = 3, /* Ethernet destination address. */ - OFPXMT_OFB_ETH_SRC = 4, /* Ethernet source address. */ - OFPXMT_OFB_ETH_TYPE = 5, /* Ethernet frame type. */ - OFPXMT_OFB_VLAN_VID = 6, /* VLAN id. */ - OFPXMT_OFB_VLAN_PCP = 7, /* VLAN priority. */ - OFPXMT_OFB_IP_DSCP = 8, /* IP DSCP (6 bits in ToS field). */ - OFPXMT_OFB_IP_ECN = 9, /* IP ECN (2 bits in ToS field). */ - OFPXMT_OFB_IP_PROTO = 10, /* IP protocol. */ - OFPXMT_OFB_IPV4_SRC = 11, /* IPv4 source address. */ - OFPXMT_OFB_IPV4_DST = 12, /* IPv4 destination address. */ - OFPXMT_OFB_TCP_SRC = 13, /* TCP source port. */ - OFPXMT_OFB_TCP_DST = 14, /* TCP destination port. */ - OFPXMT_OFB_UDP_SRC = 15, /* UDP source port. */ - OFPXMT_OFB_UDP_DST = 16, /* UDP destination port. */ - OFPXMT_OFB_SCTP_SRC = 17, /* SCTP source port. */ - OFPXMT_OFB_SCTP_DST = 18, /* SCTP destination port. */ - OFPXMT_OFB_ICMPV4_TYPE = 19, /* ICMP type. */ - OFPXMT_OFB_ICMPV4_CODE = 20, /* ICMP code. */ - OFPXMT_OFB_ARP_OP = 21, /* ARP opcode. */ - OFPXMT_OFB_ARP_SPA = 22, /* ARP source IPv4 address. */ - OFPXMT_OFB_ARP_TPA = 23, /* ARP target IPv4 address. */ - OFPXMT_OFB_ARP_SHA = 24, /* ARP source hardware address. */ - OFPXMT_OFB_ARP_THA = 25, /* ARP target hardware address. */ - OFPXMT_OFB_IPV6_SRC = 26, /* IPv6 source address. */ - OFPXMT_OFB_IPV6_DST = 27, /* IPv6 destination address. */ - OFPXMT_OFB_IPV6_FLABEL = 28, /* IPv6 Flow Label */ - OFPXMT_OFB_ICMPV6_TYPE = 29, /* ICMPv6 type. */ - OFPXMT_OFB_ICMPV6_CODE = 30, /* ICMPv6 code. */ + OFPXMT_OFB_IN_PORT = 0, /* Switch input port. */ + OFPXMT_OFB_IN_PHY_PORT = 1, /* Switch physical input port. */ + OFPXMT_OFB_METADATA = 2, /* Metadata passed between tables. */ + OFPXMT_OFB_ETH_DST = 3, /* Ethernet destination address. */ + OFPXMT_OFB_ETH_SRC = 4, /* Ethernet source address. */ + OFPXMT_OFB_ETH_TYPE = 5, /* Ethernet frame type. */ + OFPXMT_OFB_VLAN_VID = 6, /* VLAN id. */ + OFPXMT_OFB_VLAN_PCP = 7, /* VLAN priority. */ + OFPXMT_OFB_IP_DSCP = 8, /* IP DSCP (6 bits in ToS field). */ + OFPXMT_OFB_IP_ECN = 9, /* IP ECN (2 bits in ToS field). */ + OFPXMT_OFB_IP_PROTO = 10, /* IP protocol. */ + OFPXMT_OFB_IPV4_SRC = 11, /* IPv4 source address. */ + OFPXMT_OFB_IPV4_DST = 12, /* IPv4 destination address. */ + OFPXMT_OFB_TCP_SRC = 13, /* TCP source port. */ + OFPXMT_OFB_TCP_DST = 14, /* TCP destination port. */ + OFPXMT_OFB_UDP_SRC = 15, /* UDP source port. */ + OFPXMT_OFB_UDP_DST = 16, /* UDP destination port. */ + OFPXMT_OFB_SCTP_SRC = 17, /* SCTP source port. */ + OFPXMT_OFB_SCTP_DST = 18, /* SCTP destination port. */ + OFPXMT_OFB_ICMPV4_TYPE = 19, /* ICMP type. */ + OFPXMT_OFB_ICMPV4_CODE = 20, /* ICMP code. */ + OFPXMT_OFB_ARP_OP = 21, /* ARP opcode. */ + OFPXMT_OFB_ARP_SPA = 22, /* ARP source IPv4 address. */ + OFPXMT_OFB_ARP_TPA = 23, /* ARP target IPv4 address. */ + OFPXMT_OFB_ARP_SHA = 24, /* ARP source hardware address. */ + OFPXMT_OFB_ARP_THA = 25, /* ARP target hardware address. */ + OFPXMT_OFB_IPV6_SRC = 26, /* IPv6 source address. */ + OFPXMT_OFB_IPV6_DST = 27, /* IPv6 destination address. */ + OFPXMT_OFB_IPV6_FLABEL = 28, /* IPv6 Flow Label */ + OFPXMT_OFB_ICMPV6_TYPE = 29, /* ICMPv6 type. */ + OFPXMT_OFB_ICMPV6_CODE = 30, /* ICMPv6 code. */ OFPXMT_OFB_IPV6_ND_TARGET = 31, /* Target address for ND. */ - OFPXMT_OFB_IPV6_ND_SLL = 32, /* Source link-layer for ND. */ - OFPXMT_OFB_IPV6_ND_TLL = 33, /* Target link-layer for ND. */ - OFPXMT_OFB_MPLS_LABEL = 34, /* MPLS label. */ - OFPXMT_OFB_MPLS_TC = 35, /* MPLS TC. */ - OFPXMT_OFB_MPLS_BOS = 36, /* MPLS BoS bit. */ - OFPXMT_OFB_PBB_ISID = 37, /* PBB I-SID. */ - OFPXMT_OFB_TUNNEL_ID = 38, /* Logical Port Metadata. */ - OFPXMT_OFB_IPV6_EXTHDR = 39 /* IPv6 Extension Header pseudo-field */ -}; + OFPXMT_OFB_IPV6_ND_SLL = 32, /* Source link-layer for ND. */ + OFPXMT_OFB_IPV6_ND_TLL = 33, /* Target link-layer for ND. */ + OFPXMT_OFB_MPLS_LABEL = 34, /* MPLS label. */ + OFPXMT_OFB_MPLS_TC = 35, /* MPLS TC. */ + OFPXMT_OFB_MPLS_BOS = 36, /* MPLS BoS bit. */ + OFPXMT_OFB_PBB_ISID = 37, /* PBB I-SID. */ + OFPXMT_OFB_TUNNEL_ID = 38, /* Logical Port Metadata. */ + OFPXMT_OFB_IPV6_EXTHDR = 39, /* IPv6 Extension Header pseudo-field */ +}; + +#define OFPXMT_OFB_ALL ((UINT64_C(1) << 40) - 1) + +/* OpenFlow port on which the packet was received. + * May be a physical port, a logical port, or the reserved port OFPP_LOCAL + * + * Prereqs: None. + * + * Format: 32-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_IN_PORT OXM_HEADER (0x8000, OFPXMT_OFB_IN_PORT, 4) + +/* Physical port on which the packet was received. + * + * Consider a packet received on a tunnel interface defined over a link + * aggregation group (LAG) with two physical port members. If the tunnel + * interface is the logical port bound to OpenFlow. In this case, + * OFPXMT_OF_IN_PORT is the tunnel's port number and OFPXMT_OF_IN_PHY_PORT is + * the physical port number of the LAG on which the tunnel is configured. + * + * When a packet is received directly on a physical port and not processed by a + * logical port, OFPXMT_OF_IN_PORT and OFPXMT_OF_IN_PHY_PORT have the same + * value. + * + * This field is usually not available in a regular match and only available + * in ofp_packet_in messages when it's different from OXM_OF_IN_PORT. + * + * Prereqs: OXM_OF_IN_PORT must be present. + * + * Format: 32-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_IN_PHY_PORT OXM_HEADER (0x8000, OFPXMT_OFB_IN_PHY_PORT, 4) + +/* Table metadata. + * + * Prereqs: None. + * + * Format: 64-bit integer in network byte order. + * + * Masking: Arbitrary masks. + */ +#define OXM_OF_METADATA OXM_HEADER (0x8000, OFPXMT_OFB_METADATA, 8) +#define OXM_OF_METADATA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_METADATA, 8) + +/* Source or destination address in Ethernet header. + * + * Prereqs: None. + * + * Format: 48-bit Ethernet MAC address. + * + * Masking: Arbitrary masks. */ +#define OXM_OF_ETH_DST OXM_HEADER (0x8000, OFPXMT_OFB_ETH_DST, 6) +#define OXM_OF_ETH_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ETH_DST, 6) +#define OXM_OF_ETH_SRC OXM_HEADER (0x8000, OFPXMT_OFB_ETH_SRC, 6) +#define OXM_OF_ETH_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ETH_SRC, 6) + +/* Packet's Ethernet type. + * + * Prereqs: None. + * + * Format: 16-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_ETH_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ETH_TYPE, 2) /* The VLAN id is 12-bits, so we can use the entire 16 bits to indicate -* special conditions. -*/ + * special conditions. + */ enum ofp_vlan_id { OFPVID_PRESENT = 0x1000, /* Bit that indicate that a VLAN id is set */ - OFPVID_NONE = 0x0000, /* No VLAN id was set. */ -}; + OFPVID_NONE = 0x0000, /* No VLAN id was set. */ +}; +/* Define for compatibility */ +#define OFP_VLAN_NONE OFPVID_NONE + +/* 802.1Q VID. + * + * For a packet with an 802.1Q header, this is the VLAN-ID (VID) from the + * outermost tag, with the CFI bit forced to 1. For a packet with no 802.1Q + * header, this has value OFPVID_NONE. + * + * Prereqs: None. + * + * Format: 16-bit integer in network byte order with bit 13 indicating + * presence of VLAN header and 3 most-significant bits forced to 0. + * Only the lower 13 bits have meaning. + * + * Masking: Arbitrary masks. + * + * This field can be used in various ways: + * + * - If it is not constrained at all, the nx_match matches packets without + * an 802.1Q header or with an 802.1Q header that has any VID value. + * + * - Testing for an exact match with 0x0 matches only packets without + * an 802.1Q header. + * + * - Testing for an exact match with a VID value with CFI=1 matches packets + * that have an 802.1Q header with a specified VID. + * + * - Testing for an exact match with a nonzero VID value with CFI=0 does + * not make sense. The switch may reject this combination. + * + * - Testing with nxm_value=0, nxm_mask=0x0fff matches packets with no 802.1Q + * header or with an 802.1Q header with a VID of 0. + * + * - Testing with nxm_value=0x1000, nxm_mask=0x1000 matches packets with + * an 802.1Q header that has any VID value. + */ +#define OXM_OF_VLAN_VID OXM_HEADER (0x8000, OFPXMT_OFB_VLAN_VID, 2) +#define OXM_OF_VLAN_VID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_VLAN_VID, 2) + +/* 802.1Q PCP. + * + * For a packet with an 802.1Q header, this is the VLAN-PCP from the + * outermost tag. For a packet with no 802.1Q header, this has value + * 0. + * + * Prereqs: OXM_OF_VLAN_VID must be different from OFPVID_NONE. + * + * Format: 8-bit integer with 5 most-significant bits forced to 0. + * Only the lower 3 bits have meaning. + * + * Masking: Not maskable. + */ +#define OXM_OF_VLAN_PCP OXM_HEADER (0x8000, OFPXMT_OFB_VLAN_PCP, 1) + +/* The Diff Serv Code Point (DSCP) bits of the IP header. + * Part of the IPv4 ToS field or the IPv6 Traffic Class field. + * + * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd. + * + * Format: 8-bit integer with 2 most-significant bits forced to 0. + * Only the lower 6 bits have meaning. + * + * Masking: Not maskable. */ +#define OXM_OF_IP_DSCP OXM_HEADER (0x8000, OFPXMT_OFB_IP_DSCP, 1) + +/* The ECN bits of the IP header. + * Part of the IPv4 ToS field or the IPv6 Traffic Class field. + * + * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd. + * + * Format: 8-bit integer with 6 most-significant bits forced to 0. + * Only the lower 2 bits have meaning. + * + * Masking: Not maskable. */ +#define OXM_OF_IP_ECN OXM_HEADER (0x8000, OFPXMT_OFB_IP_ECN, 1) + +/* The "protocol" byte in the IP header. + * + * Prereqs: OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd. + * + * Format: 8-bit integer. + * + * Masking: Not maskable. */ +#define OXM_OF_IP_PROTO OXM_HEADER (0x8000, OFPXMT_OFB_IP_PROTO, 1) + +/* The source or destination address in the IP header. + * + * Prereqs: OXM_OF_ETH_TYPE must match 0x0800 exactly. + * + * Format: 32-bit integer in network byte order. + * + * Masking: Arbitrary masks. + */ +#define OXM_OF_IPV4_SRC OXM_HEADER (0x8000, OFPXMT_OFB_IPV4_SRC, 4) +#define OXM_OF_IPV4_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV4_SRC, 4) +#define OXM_OF_IPV4_DST OXM_HEADER (0x8000, OFPXMT_OFB_IPV4_DST, 4) +#define OXM_OF_IPV4_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV4_DST, 4) + +/* The source or destination port in the TCP header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd. + * OXM_OF_IP_PROTO must match 6 exactly. + * + * Format: 16-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_TCP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_TCP_SRC, 2) +#define OXM_OF_TCP_DST OXM_HEADER (0x8000, OFPXMT_OFB_TCP_DST, 2) + +/* The source or destination port in the UDP header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd. + * OXM_OF_IP_PROTO must match 17 exactly. + * + * Format: 16-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_UDP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_UDP_SRC, 2) +#define OXM_OF_UDP_DST OXM_HEADER (0x8000, OFPXMT_OFB_UDP_DST, 2) + +/* The source or destination port in the SCTP header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match either 0x0800 or 0x86dd. + * OXM_OF_IP_PROTO must match 132 exactly. + * + * Format: 16-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_SCTP_SRC OXM_HEADER (0x8000, OFPXMT_OFB_SCTP_SRC, 2) +#define OXM_OF_SCTP_DST OXM_HEADER (0x8000, OFPXMT_OFB_SCTP_DST, 2) + +/* The type or code in the ICMP header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x0800 exactly. + * OXM_OF_IP_PROTO must match 1 exactly. + * + * Format: 8-bit integer. + * + * Masking: Not maskable. */ +#define OXM_OF_ICMPV4_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV4_TYPE, 1) +#define OXM_OF_ICMPV4_CODE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV4_CODE, 1) + +/* ARP opcode. + * + * For an Ethernet+IP ARP packet, the opcode in the ARP header. Always 0 + * otherwise. + * + * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly. + * + * Format: 16-bit integer in network byte order. + * + * Masking: Not maskable. */ +#define OXM_OF_ARP_OP OXM_HEADER (0x8000, OFPXMT_OFB_ARP_OP, 2) + +/* For an Ethernet+IP ARP packet, the source or target protocol address + * in the ARP header. Always 0 otherwise. + * + * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly. + * + * Format: 32-bit integer in network byte order. + * + * Masking: Arbitrary masks. + */ +#define OXM_OF_ARP_SPA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_SPA, 4) +#define OXM_OF_ARP_SPA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ARP_SPA, 4) +#define OXM_OF_ARP_TPA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_TPA, 4) +#define OXM_OF_ARP_TPA_W OXM_HEADER_W(0x8000, OFPXMT_OFB_ARP_TPA, 4) + +/* For an Ethernet+IP ARP packet, the source or target hardware address + * in the ARP header. Always 0 otherwise. + * + * Prereqs: OXM_OF_ETH_TYPE must match 0x0806 exactly. + * + * Format: 48-bit Ethernet MAC address. + * + * Masking: Not maskable. */ +#define OXM_OF_ARP_SHA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_SHA, 6) +#define OXM_OF_ARP_SHA_W OXM_HEADER_W (0x8000, OFPXMT_OFB_ARP_SHA, 6) +#define OXM_OF_ARP_THA OXM_HEADER (0x8000, OFPXMT_OFB_ARP_THA, 6) +#define OXM_OF_ARP_THA_W OXM_HEADER_W (0x8000, OFPXMT_OFB_ARP_THA, 6) + + +/* The source or destination address in the IPv6 header. + * + * Prereqs: OXM_OF_ETH_TYPE must match 0x86dd exactly. + * + * Format: 128-bit IPv6 address. + * + * Masking: Arbitrary masks. + */ +#define OXM_OF_IPV6_SRC OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_SRC, 16) +#define OXM_OF_IPV6_SRC_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_SRC, 16) +#define OXM_OF_IPV6_DST OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_DST, 16) +#define OXM_OF_IPV6_DST_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_DST, 16) + +/* The IPv6 Flow Label + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly + * + * Format: 32-bit integer with 12 most-significant bits forced to 0. + * Only the lower 20 bits have meaning. + * + * Masking: Arbitrary masks. + */ +#define OXM_OF_IPV6_FLABEL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_FLABEL, 4) +#define OXM_OF_IPV6_FLABEL_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_FLABEL, 4) + +/* The type or code in the ICMPv6 header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly. + * OXM_OF_IP_PROTO must match 58 exactly. + * + * Format: 8-bit integer. + * + * Masking: Not maskable. */ +#define OXM_OF_ICMPV6_TYPE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV6_TYPE, 1) +#define OXM_OF_ICMPV6_CODE OXM_HEADER (0x8000, OFPXMT_OFB_ICMPV6_CODE, 1) + +/* The target address in an IPv6 Neighbor Discovery message. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly. + * OXM_OF_IP_PROTO must match 58 exactly. + * OXM_OF_ICMPV6_TYPE must be either 135 or 136. + * + * Format: 128-bit IPv6 address. + * + * Masking: Not maskable. */ +#define OXM_OF_IPV6_ND_TARGET OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_TARGET, 16) + +/* The source link-layer address option in an IPv6 Neighbor Discovery + * message. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly. + * OXM_OF_IP_PROTO must match 58 exactly. + * OXM_OF_ICMPV6_TYPE must be exactly 135. + * + * Format: 48-bit Ethernet MAC address. + * + * Masking: Not maskable. */ +#define OXM_OF_IPV6_ND_SLL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_SLL, 6) + +/* The target link-layer address option in an IPv6 Neighbor Discovery + * message. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly. + * OXM_OF_IP_PROTO must match 58 exactly. + * OXM_OF_ICMPV6_TYPE must be exactly 136. + * + * Format: 48-bit Ethernet MAC address. + * + * Masking: Not maskable. */ +#define OXM_OF_IPV6_ND_TLL OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_ND_TLL, 6) + +/* The LABEL in the first MPLS shim header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly. + * + * Format: 32-bit integer in network byte order with 12 most-significant + * bits forced to 0. Only the lower 20 bits have meaning. + * + * Masking: Not maskable. */ +#define OXM_OF_MPLS_LABEL OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_LABEL, 4) + +/* The TC in the first MPLS shim header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly. + * + * Format: 8-bit integer with 5 most-significant bits forced to 0. + * Only the lower 3 bits have meaning. + * + * Masking: Not maskable. */ +#define OXM_OF_MPLS_TC OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_TC, 1) + +/* The BoS bit in the first MPLS shim header. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x8847 or 0x8848 exactly. + * + * Format: 8-bit integer with 7 most-significant bits forced to 0. + * Only the lowest bit have a meaning. + * + * Masking: Not maskable. */ +#define OXM_OF_MPLS_BOS OXM_HEADER (0x8000, OFPXMT_OFB_MPLS_BOS, 1) + +/* IEEE 802.1ah I-SID. + * + * For a packet with a PBB header, this is the I-SID from the + * outermost service tag. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x88E7 exactly. + * + * Format: 24-bit integer in network byte order. + * + * Masking: Arbitrary masks. */ +#define OXM_OF_PBB_ISID OXM_HEADER (0x8000, OFPXMT_OFB_PBB_ISID, 3) +#define OXM_OF_PBB_ISID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_PBB_ISID, 3) + +/* Logical Port Metadata. + * + * Metadata associated with a logical port. + * If the logical port performs encapsulation and decapsulation, this + * is the demultiplexing field from the encapsulation header. + * For example, for a packet received via GRE tunnel including a (32-bit) key, + * the key is stored in the low 32-bits and the high bits are zeroed. + * For a MPLS logical port, the low 20 bits represent the MPLS Label. + * For a VxLAN logical port, the low 24 bits represent the VNI. + * If the packet is not received through a logical port, the value is 0. + * + * Prereqs: None. + * + * Format: 64-bit integer in network byte order. + * + * Masking: Arbitrary masks. */ +#define OXM_OF_TUNNEL_ID OXM_HEADER (0x8000, OFPXMT_OFB_TUNNEL_ID, 8) +#define OXM_OF_TUNNEL_ID_W OXM_HEADER_W(0x8000, OFPXMT_OFB_TUNNEL_ID, 8) + +/* The IPv6 Extension Header pseudo-field. + * + * Prereqs: + * OXM_OF_ETH_TYPE must match 0x86dd exactly + * + * Format: 16-bit integer with 7 most-significant bits forced to 0. + * Only the lower 9 bits have meaning. + * + * Masking: Maskable. */ +#define OXM_OF_IPV6_EXTHDR OXM_HEADER (0x8000, OFPXMT_OFB_IPV6_EXTHDR, 2) +#define OXM_OF_IPV6_EXTHDR_W OXM_HEADER_W(0x8000, OFPXMT_OFB_IPV6_EXTHDR, 2) /* Bit definitions for IPv6 Extension Header pseudo-field. */ -enum ofp_ipv6exthdr_flags { - OFPIEH_NONEXT = 1 << 0, /* "No next header" encountered. */ - OFPIEH_ESP = 1 << 1, /* Encrypted Sec Payload header present. */ - OFPIEH_AUTH = 1 << 2, /* Authentication header present. */ - OFPIEH_DEST = 1 << 3, /* 1 or 2 dest headers present. */ - OFPIEH_FRAG = 1 << 4, /* Fragment header present. */ - OFPIEH_ROUTER = 1 << 5, /* Router header present. */ - OFPIEH_HOP = 1 << 6, /* Hop-by-hop header present. */ - OFPIEH_UNREP = 1 << 7, /* Unexpected repeats encountered. */ - OFPIEH_UNSEQ = 1 << 8, /* Unexpected sequencing encountered. */ -}; - -/* Header for OXM experimenter match fields. */ +enum ofp_ipv6exthdr_flags { + OFPIEH_NONEXT = 1 << 0, /* "No next header" encountered. */ + OFPIEH_ESP = 1 << 1, /* Encrypted Sec Payload header present. */ + OFPIEH_AUTH = 1 << 2, /* Authentication header present. */ + OFPIEH_DEST = 1 << 3, /* 1 or 2 dest headers present. */ + OFPIEH_FRAG = 1 << 4, /* Fragment header present. */ + OFPIEH_ROUTER = 1 << 5, /* Router header present. */ + OFPIEH_HOP = 1 << 6, /* Hop-by-hop header present. */ + OFPIEH_UNREP = 1 << 7, /* Unexpected repeats encountered. */ + OFPIEH_UNSEQ = 1 << 8, /* Unexpected sequencing encountered. */ +}; + +/* Header for OXM experimenter match fields. + * The experimenter class should not use OXM_HEADER() macros for defining + * fields due to this extra header. */ struct ofp_oxm_experimenter_header { - uint32_t oxm_header; /* oxm_class = OFPXMC_EXPERIMENTER */ - uint32_t experimenter; /* Experimenter ID which takes the same - form as in struct ofp_experimenter_header. */ + uint32_t oxm_header; /* oxm_class = OFPXMC_EXPERIMENTER */ + uint32_t experimenter; /* Experimenter ID which takes the same + form as in struct ofp_experimenter_header. */ }; OFP_ASSERT(sizeof(struct ofp_oxm_experimenter_header) == 8); -enum ofp_instruction_type { - OFPIT_GOTO_TABLE = 1, /* Setup the next table in the lookup */ - OFPIT_WRITE_METADATA = 2, /* Setup the metadata field for use later in - pipeline */ - OFPIT_WRITE_ACTIONS = 3, /* Write the action(s) onto the datapath action - set */ - OFPIT_APPLY_ACTIONS = 4, /* Applies the action(s) immediately */ - OFPIT_CLEAR_ACTIONS = 5, /* Clears all actions from the datapath - action set */ - OFPIT_METER = 6, /* Apply meter (rate limiter) */ - - OFPIT_EXPERIMENTER = 0xFFFF /* Experimenter instruction */ -}; - -/* Generic ofp_instruction structure */ -struct ofp_instruction { - uint16_t type; /* Instruction type */ - uint16_t len; /* Length of this struct in bytes. */ - uint8_t pad[4]; /* Align to 64-bits */ -}; -OFP_ASSERT(sizeof(struct ofp_instruction) == 8); - -/* Instruction structure for OFPIT_GOTO_TABLE */ -struct ofp_instruction_goto_table { - uint16_t type; /* OFPIT_GOTO_TABLE */ - uint16_t len; /* Length of this struct in bytes. */ - uint8_t table_id; /* Set next table in the lookup pipeline */ - uint8_t pad[3]; /* Pad to 64 bits. */ -}; -OFP_ASSERT(sizeof(struct ofp_instruction_goto_table) == 8); - -/* Instruction structure for OFPIT_WRITE_METADATA */ -struct ofp_instruction_write_metadata { - uint16_t type; /* OFPIT_WRITE_METADATA */ - uint16_t len; /* Length of this struct in bytes. */ - uint8_t pad[4]; /* Align to 64-bits */ - uint64_t metadata; /* Metadata value to write */ - uint64_t metadata_mask; /* Metadata write bitmask */ -}; -OFP_ASSERT(sizeof(struct ofp_instruction_write_metadata) == 24); - -/* 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); - -/* Instruction structure for OFPIT_WRITE/APPLY/CLEAR_ACTIONS */ -struct ofp_instruction_actions { - uint16_t type; /* One of OFPIT_*_ACTIONS */ - uint16_t len; /* Length of this struct in bytes. */ - uint8_t pad[4]; /* Align to 64-bits */ - struct ofp_action_header actions[0]; /* Actions associated with - OFPIT_WRITE_ACTIONS and - OFPIT_APPLY_ACTIONS */ -}; -OFP_ASSERT(sizeof(struct ofp_instruction_actions) == 8); - -/* Instruction structure for OFPIT_METER */ -struct ofp_instruction_meter { - uint16_t type; /* OFPIT_METER */ - uint16_t len; /* Length is 8. */ - uint32_t meter_id; /* Meter instance. */ -}; -OFP_ASSERT(sizeof(struct ofp_instruction_meter) == 8); - +/* ## ----------------- ## */ +/* ## OpenFlow Actions. ## */ +/* ## ----------------- ## */ enum ofp_action_type { - OFPAT_OUTPUT = 0, /* Output to switch port. */ + OFPAT_OUTPUT = 0, /* Output to switch port. */ OFPAT_COPY_TTL_OUT = 11, /* Copy TTL "outwards" -- from next-to-outermost to outermost */ - OFPAT_COPY_TTL_IN = 12, /* Copy TTL "inwards" -- from outermost to - next-to-outermost */ + OFPAT_COPY_TTL_IN = 12, /* Copy TTL "inwards" -- from outermost to + next-to-outermost */ OFPAT_SET_MPLS_TTL = 15, /* MPLS TTL */ OFPAT_DEC_MPLS_TTL = 16, /* Decrement MPLS TTL */ - OFPAT_PUSH_VLAN = 17, /* Push a new VLAN tag */ - OFPAT_POP_VLAN = 18, /* Pop the outer VLAN tag */ - OFPAT_PUSH_MPLS = 19, /* Push a new MPLS tag */ - OFPAT_POP_MPLS = 20, /* Pop the outer MPLS tag */ - OFPAT_SET_QUEUE = 21, /* Set queue id when outputting to a port */ - OFPAT_GROUP = 22, /* Apply group. */ - OFPAT_SET_NW_TTL = 23, /* IP TTL. */ - OFPAT_DEC_NW_TTL = 24, /* Decrement IP TTL. */ - OFPAT_SET_FIELD = 25, /* Set a header field using OXM TLV format. */ - OFPAT_PUSH_PBB = 26, /*Push a new PBB service tag (I-TAG) */ - OFPAT_POP_PBB = 27, /* Pop the outer PBB service tag (I-TAG) */ + + OFPAT_PUSH_VLAN = 17, /* Push a new VLAN tag */ + OFPAT_POP_VLAN = 18, /* Pop the outer VLAN tag */ + OFPAT_PUSH_MPLS = 19, /* Push a new MPLS tag */ + OFPAT_POP_MPLS = 20, /* Pop the outer MPLS tag */ + OFPAT_SET_QUEUE = 21, /* Set queue id when outputting to a port */ + OFPAT_GROUP = 22, /* Apply group. */ + OFPAT_SET_NW_TTL = 23, /* IP TTL. */ + OFPAT_DEC_NW_TTL = 24, /* Decrement IP TTL. */ + OFPAT_SET_FIELD = 25, /* Set a header field using OXM TLV format. */ + OFPAT_PUSH_PBB = 26, /* Push a new PBB service tag (I-TAG) */ + OFPAT_POP_PBB = 27, /* Pop the outer PBB service tag (I-TAG) */ OFPAT_EXPERIMENTER = 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. A ’max_len’ of OFPCML_NO_BUFFER means that -* the packet is not buffered and the complete packet is to be sent to -* the controller. */ -struct ofp_action_output { - uint16_t type; /* OFPAT_OUTPUT. */ - uint16_t len; /* Length is 16. */ - uint32_t port; /* Output port. */ - uint16_t max_len; /* Max length to send to controller. */ - uint8_t pad[6]; /* Pad to 64 bits. */ +/* 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_output) == 16); +OFP_ASSERT(sizeof(struct ofp_action_header) == 8); enum ofp_controller_max_len { - OFPCML_MAX = 0xffe5, /* maximum max_len value which can be used - to request a specific byte length. */ - OFPCML_NO_BUFFER = 0xffff /* indicates that no buffering should be - applied and the whole packet is to be - sent to the controller. */ -}; - -/* Action structure for OFPAT_GROUP. */ -struct ofp_action_group { - uint16_t type; /* OFPAT_GROUP. */ - uint16_t len; /* Length is 8. */ - uint32_t group_id; /* Group identifier. */ -}; -OFP_ASSERT(sizeof(struct ofp_action_group) == 8); - -/* OFPAT_SET_QUEUE action struct: send packets to given queue on port. */ -struct ofp_action_set_queue { - uint16_t type; /* OFPAT_SET_QUEUE. */ - uint16_t len; /* Len is 8. */ - uint32_t queue_id; /* Queue id for the packets. */ + OFPCML_MAX = 0xffe5, /* maximum max_len value which can be used + to request a specific byte length. */ + OFPCML_NO_BUFFER = 0xffff /* indicates that no buffering should be + applied and the whole packet is to be + sent to the controller. */ +}; + +/* 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. A 'max_len' of OFPCML_NO_BUFFER means that + * the packet is not buffered and the complete packet is to be sent to + * the controller. */ +struct ofp_action_output { + uint16_t type; /* OFPAT_OUTPUT. */ + uint16_t len; /* Length is 16. */ + uint32_t port; /* Output port. */ + uint16_t max_len; /* Max length to send to controller. */ + uint8_t pad[6]; /* Pad to 64 bits. */ }; -OFP_ASSERT(sizeof(struct ofp_action_set_queue) == 8); +OFP_ASSERT(sizeof(struct ofp_action_output) == 16); /* Action structure for OFPAT_SET_MPLS_TTL. */ struct ofp_action_mpls_ttl { - uint16_t type; /* OFPAT_SET_MPLS_TTL. */ - uint16_t len; /* Length is 8. */ - uint8_t mpls_ttl; /* MPLS TTL */ - uint8_t pad[3]; + uint16_t type; /* OFPAT_SET_MPLS_TTL. */ + uint16_t len; /* Length is 8. */ + uint8_t mpls_ttl; /* MPLS TTL */ + uint8_t pad[3]; }; OFP_ASSERT(sizeof(struct ofp_action_mpls_ttl) == 8); -/* Action structure for OFPAT_SET_NW_TTL. */ -struct ofp_action_nw_ttl { - uint16_t type; /* OFPAT_SET_NW_TTL. */ - uint16_t len; /* Length is 8. */ - uint8_t nw_ttl; /* IP TTL */ - uint8_t pad[3]; -}; -OFP_ASSERT(sizeof(struct ofp_action_nw_ttl) == 8); - /* Action structure for OFPAT_PUSH_VLAN/MPLS/PBB. */ struct ofp_action_push { - uint16_t type; /* OFPAT_PUSH_VLAN/MPLS/PBB. */ - uint16_t len; /* Length is 8. */ - uint16_t ethertype; /* Ethertype */ - uint8_t pad[2]; + uint16_t type; /* OFPAT_PUSH_VLAN/MPLS/PBB. */ + uint16_t len; /* Length is 8. */ + uint16_t ethertype; /* Ethertype */ + uint8_t pad[2]; }; OFP_ASSERT(sizeof(struct ofp_action_push) == 8); /* Action structure for OFPAT_POP_MPLS. */ struct ofp_action_pop_mpls { - uint16_t type; /* OFPAT_POP_MPLS. */ - uint16_t len; /* Length is 8. */ - uint16_t ethertype; /* Ethertype */ - uint8_t pad[2]; + uint16_t type; /* OFPAT_POP_MPLS. */ + uint16_t len; /* Length is 8. */ + uint16_t ethertype; /* Ethertype */ + uint8_t pad[2]; }; OFP_ASSERT(sizeof(struct ofp_action_pop_mpls) == 8); +/* Action structure for OFPAT_GROUP. */ +struct ofp_action_group { + uint16_t type; /* OFPAT_GROUP. */ + uint16_t len; /* Length is 8. */ + uint32_t group_id; /* Group identifier. */ +}; +OFP_ASSERT(sizeof(struct ofp_action_group) == 8); + +/* Action structure for OFPAT_SET_NW_TTL. */ +struct ofp_action_nw_ttl { + uint16_t type; /* OFPAT_SET_NW_TTL. */ + uint16_t len; /* Length is 8. */ + uint8_t nw_ttl; /* IP TTL */ + uint8_t pad[3]; +}; +OFP_ASSERT(sizeof(struct ofp_action_nw_ttl) == 8); + /* Action structure for OFPAT_SET_FIELD. */ struct ofp_action_set_field { - uint16_t type; /* OFPAT_SET_FIELD. */ - uint16_t len; /* Length is padded to 64 bits. */ - /* Followed by: - * -Exactly oxm_len bytes containing a single OXM TLV,then - * -Exactly((oxm_len + 4) + 7)/8*8 - (oxm_len +4)(between 0 and 7) - * bytes of all - zerobytes - */ - uint8_t field[4]; /* OXM TLV - Make compiler happy */ + uint16_t type; /* OFPAT_SET_FIELD. */ + uint16_t len; /* Length is padded to 64 bits. */ + /* Followed by: + * - Exactly (4 + oxm_length) bytes containing a single OXM TLV, then + * - Exactly ((8 + oxm_length) + 7)/8*8 - (8 + oxm_length) + * (between 0 and 7) bytes of all-zero bytes + */ + uint8_t field[4]; /* OXM TLV - Make compiler happy */ }; OFP_ASSERT(sizeof(struct ofp_action_set_field) == 8); /* Action header for OFPAT_EXPERIMENTER. -* The rest of the body is experimenter-defined. */ + * The rest of the body is experimenter-defined. */ struct ofp_action_experimenter_header { - uint16_t type; /* OFPAT_EXPERIMENTER. */ - uint16_t len; /* Length is a multiple of 8. */ - uint32_t experimenter; /* Experimenter ID which takes the same - form as in struct - ofp_experimenter_header. */ + uint16_t type; /* OFPAT_EXPERIMENTER. */ + uint16_t len; /* Length is a multiple of 8. */ + uint32_t experimenter; /* Experimenter ID which takes the same + form as in struct + ofp_experimenter_header. */ }; OFP_ASSERT(sizeof(struct ofp_action_experimenter_header) == 8); +/* ## ---------------------- ## */ +/* ## OpenFlow Instructions. ## */ +/* ## ---------------------- ## */ -/*************Controller-to-Switch Messages******************/ +enum ofp_instruction_type { + OFPIT_GOTO_TABLE = 1, /* Setup the next table in the lookup + pipeline */ + OFPIT_WRITE_METADATA = 2, /* Setup the metadata field for use later in + pipeline */ + OFPIT_WRITE_ACTIONS = 3, /* Write the action(s) onto the datapath action + set */ + OFPIT_APPLY_ACTIONS = 4, /* Applies the action(s) immediately */ + OFPIT_CLEAR_ACTIONS = 5, /* Clears all actions from the datapath + action set */ + OFPIT_METER = 6, /* Apply meter (rate limiter) */ -/* 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 auxiliary_id; /* Identify auxiliary connections. */ - uint8_t pad[2]; /* Align to 64-bits. */ - /* Features. */ - uint32_t capabilities; /* Bitmap of support "ofp_capabilities". */ - uint32_t reserved; + OFPIT_EXPERIMENTER = 0xFFFF /* Experimenter instruction */ }; -OFP_ASSERT(sizeof(struct ofp_switch_features) == 32); -/* 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_GROUP_STATS = 1 << 3, /* Group statistics. */ - OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ - OFPC_QUEUE_STATS = 1 << 6, /* Queue statistics. */ - OFPC_PORT_BLOCKED = 1 << 8 /* Switch will block looping ports. */ +/* Instruction header that is common to all instructions. The length includes + * the header and any padding used to make the instruction 64-bit aligned. + * NB: The length of an instruction *must* always be a multiple of eight. */ +struct ofp_instruction { + uint16_t type; /* Instruction type */ + uint16_t len; /* Length of this struct in bytes. */ }; +OFP_ASSERT(sizeof(struct ofp_instruction) == 4); -/* 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. See - ofp_controller_max_len for valid values.*/ +/* Instruction structure for OFPIT_GOTO_TABLE */ +struct ofp_instruction_goto_table { + uint16_t type; /* OFPIT_GOTO_TABLE */ + uint16_t len; /* Length of this struct in bytes. */ + uint8_t table_id; /* Set next table in the lookup pipeline */ + uint8_t pad[3]; /* Pad to 64 bits. */ }; -OFP_ASSERT(sizeof(struct ofp_switch_config) == 12); +OFP_ASSERT(sizeof(struct ofp_instruction_goto_table) == 8); -enum ofp_config_flags { - /* Handling of IP fragments. */ - OFPC_FRAG_NORMAL = 0, /* No special handling for fragments. */ - OFPC_FRAG_DROP = 1 << 0, /* Drop fragments. */ - OFPC_FRAG_REASM = 1 << 1, /* Reassemble (only if OFPC_IP_REASM set). */ - OFPC_FRAG_MASK = 3, - /* TTL processing - applicable for IP and MPLS packets */ - OFPC_INVALID_TTL_TO_CONTROLLER = 1 << 2, /* Send packets with invalid TTL -to the controller */ +/* Instruction structure for OFPIT_WRITE_METADATA */ +struct ofp_instruction_write_metadata { + uint16_t type; /* OFPIT_WRITE_METADATA */ + uint16_t len; /* Length of this struct in bytes. */ + uint8_t pad[4]; /* Align to 64-bits */ + uint64_t metadata; /* Metadata value to write */ + uint64_t metadata_mask; /* Metadata write bitmask */ }; +OFP_ASSERT(sizeof(struct ofp_instruction_write_metadata) == 24); -/* Table numbering. Tables can use any number up to OFPT_MAX. */ -enum ofp_table { - /* Last usable table number. */ - OFPTT_MAX = 0xfe, - /* Fake tables. */ - OFPTT_ALL = 0xff /* Wildcard table used for table config, - flow stats and flow deletes. */ +/* Instruction structure for OFPIT_WRITE/APPLY/CLEAR_ACTIONS */ +struct ofp_instruction_actions { + uint16_t type; /* One of OFPIT_*_ACTIONS */ + uint16_t len; /* Length of this struct in bytes. */ + uint8_t pad[4]; /* Align to 64-bits */ + struct ofp_action_header actions[0]; /* 0 or more actions associated with + OFPIT_WRITE_ACTIONS and + OFPIT_APPLY_ACTIONS */ }; +OFP_ASSERT(sizeof(struct ofp_instruction_actions) == 8); -/* Configure/Modify behavior of a flow table */ -struct ofp_table_mod { - struct ofp_header header; - uint8_t table_id; /* ID of the table, OFPTT_ALL indicates all tables */ - uint8_t pad[3]; /* Pad to 32 bits */ - uint32_t config; /* Bitmap of OFPTC_* flags */ +/* Instruction structure for OFPIT_METER */ +struct ofp_instruction_meter { + uint16_t type; /* OFPIT_METER */ + uint16_t len; /* Length is 8. */ + uint32_t meter_id; /* Meter instance. */ }; -OFP_ASSERT(sizeof(struct ofp_table_mod) == 16); +OFP_ASSERT(sizeof(struct ofp_instruction_meter) == 8); -enum ofp_table_config { - OFPTC_TABLE_MISS_CONTROLLER = 0, /* Send to controller. */ - OFPTC_TABLE_MISS_CONTINUE = 1 << 0, /* Continue to the next table in the - pipeline (OpenFlow 1.0 behavior). */ - OFPTC_TABLE_MISS_DROP = 1 << 1, /* Drop the packet. */ - OFPTC_TABLE_MISS_MASK = 3 +/* Instruction structure for experimental instructions */ +struct ofp_instruction_experimenter { + uint16_t type; /* OFPIT_EXPERIMENTER */ + uint16_t len; /* Length of this struct in bytes */ + uint32_t experimenter; /* Experimenter ID which takes the same form + as in struct ofp_experimenter_header. */ + /* Experimenter-defined arbitrary additional data. */ }; +OFP_ASSERT(sizeof(struct ofp_instruction_experimenter) == 8); -#define OFP_DEFAULT_PRIORITY 0x8000 -#define OFP_FLOW_PERMANENT 0 - -/* Flow setup and teardown (controller -> datapath). */ -struct ofp_flow_mod { - struct ofp_header header; - uint64_t cookie; /* Opaque controller-issued identifier. */ - uint64_t cookie_mask; /* Mask used to restrict the cookie bits - that must match when the command is - OFPFC_MODIFY* or OFPFC_DELETE*. A value - of 0 indicates no restriction. */ - /* Flow actions. */ - uint8_t table_id; /* ID of the table to put the flow in. - For OFPFC_DELETE_* commands, OFPTT_ALL - can also be used to delete matching - flows from all tables. */ - uint8_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 - OFP_NO_BUFFER. - Not meaningful for OFPFC_DELETE*. */ - uint32_t out_port; /* For OFPFC_DELETE* commands, require - matching entries to include this as an - output port. A value of OFPP_ANY - indicates no restriction. */ - uint32_t out_group; /* For OFPFC_DELETE* commands, require - matching entries to include this as an - output group. A value of OFPG_ANY - indicates no restriction. */ - uint16_t flags; /* One of OFPFF_*. */ - uint8_t pad[2]; - struct ofp_match match; /* Fields to match. Variable size. */ - //struct ofp_instruction instructions[0]; /* Instruction set */ -}; -OFP_ASSERT(sizeof(struct ofp_flow_mod) == 56); +/* ## --------------------------- ## */ +/* ## OpenFlow Flow Modification. ## */ +/* ## --------------------------- ## */ enum ofp_flow_mod_command { - OFPFC_ADD = 0, /* New flow. */ - OFPFC_MODIFY = 1, /* Modify all matching flows. */ + OFPFC_ADD = 0, /* New flow. */ + OFPFC_MODIFY = 1, /* Modify all matching flows. */ OFPFC_MODIFY_STRICT = 2, /* Modify entry strictly matching wildcards and priority. */ - OFPFC_DELETE = 3, /* Delete all matching flows. */ + OFPFC_DELETE = 3, /* Delete all matching flows. */ OFPFC_DELETE_STRICT = 4, /* Delete entry strictly matching wildcards and priority. */ }; +/* 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_RESET_COUNTS = 1 << 2, /* Reset flow packet and byte counts. */ - OFPFF_NO_PKT_COUNTS = 1 << 3, /* Don’t keep track of packet count. */ - OFPFF_NO_BYT_COUNTS = 1 << 4 /*Don’t keep track of byte count. */ + 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_RESET_COUNTS = 1 << 2, /* Reset flow packet and byte counts. */ + OFPFF_NO_PKT_COUNTS = 1 << 3, /* Don't keep track of packet count. */ + OFPFF_NO_BYT_COUNTS = 1 << 4, /* Don't keep track of byte count. */ }; +/* Flow setup and teardown (controller -> datapath). */ +struct ofp_flow_mod { + struct ofp_header header; + uint64_t cookie; /* Opaque controller-issued identifier. */ + uint64_t cookie_mask; /* Mask used to restrict the cookie bits + that must match when the command is + OFPFC_MODIFY* or OFPFC_DELETE*. A value + of 0 indicates no restriction. */ + uint8_t table_id; /* ID of the table to put the flow in. + For OFPFC_DELETE_* commands, OFPTT_ALL + can also be used to delete matching + flows from all tables. */ + uint8_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 + OFP_NO_BUFFER. + Not meaningful for OFPFC_DELETE*. */ + uint32_t out_port; /* For OFPFC_DELETE* commands, require + matching entries to include this as an + output port. A value of OFPP_ANY + indicates no restriction. */ + uint32_t out_group; /* For OFPFC_DELETE* commands, require + matching entries to include this as an + output group. A value of OFPG_ANY + indicates no restriction. */ + uint16_t flags; /* Bitmap of OFPFF_* flags. */ + uint8_t pad[2]; + struct ofp_match match; /* Fields to match. Variable size. */ + /* The variable size and padded match is always followed by instructions. */ + /*struct ofp_instruction instructions[0];*/ /* Instruction set - 0 or more. + The length of the instruction + set is inferred from the + length field in the header. */ +}; +OFP_ASSERT(sizeof(struct ofp_flow_mod) == 56); + /* Group numbering. Groups can use any number up to OFPG_MAX. */ enum ofp_group { /* Last usable group number. */ @@ -698,299 +1209,631 @@ enum ofp_group { /* Fake groups. */ OFPG_ALL = 0xfffffffc, /* Represents all groups for group delete commands. */ - OFPG_ANY = 0xffffffff /* Wildcard group used only for flow stats - requests. Selects all flows regardless of - group (including flows with no group).*/ + OFPG_ANY = 0xffffffff /* Special wildcard: no group specified. */ +}; + +/* Group commands */ +enum ofp_group_mod_command { + OFPGC_ADD = 0, /* New group. */ + OFPGC_MODIFY = 1, /* Modify all matching groups. */ + OFPGC_DELETE = 2, /* Delete all matching groups. */ }; /* Bucket for use in groups. */ struct ofp_bucket { - uint16_t len; /* Length the bucket in bytes, including - this header and any padding to make it - 64-bit aligned. */ - uint16_t weight; /* Relative weight of bucket. Only - defined for select groups. */ - uint32_t watch_port; /* Port whose state affects whether this - bucket is live. Only required for fast - failover groups. */ - uint32_t watch_group; /* Group whose state affects whether this - bucket is live. Only required for fast - failover groups. */ - uint8_t pad[4]; - struct ofp_action_header actions[0]; /* The action length is inferred - from the length field in the - header. */ + uint16_t len; /* Length of the bucket in bytes, including + this header and any padding to make it + 64-bit aligned. */ + uint16_t weight; /* Relative weight of bucket. Only + defined for select groups. */ + uint32_t watch_port; /* Port whose state affects whether this + bucket is live. Only required for fast + failover groups. */ + uint32_t watch_group; /* Group whose state affects whether this + bucket is live. Only required for fast + failover groups. */ + uint8_t pad[4]; + struct ofp_action_header actions[0]; /* 0 or more actions associated with + the bucket - The action list length + is inferred from the length + of the bucket. */ }; OFP_ASSERT(sizeof(struct ofp_bucket) == 16); /* Group setup and teardown (controller -> datapath). */ struct ofp_group_mod { - struct ofp_header header; - uint16_t command; /* One of OFPGC_*. */ - uint8_t type; /* One of OFPGT_*. */ - uint8_t pad; /* Pad to 64 bits. */ - uint32_t group_id; /* Group identifier. */ - struct ofp_bucket buckets[0]; /* The length of the bucket array is inferred + struct ofp_header header; + uint16_t command; /* One of OFPGC_*. */ + uint8_t type; /* One of OFPGT_*. */ + uint8_t pad; /* Pad to 64 bits. */ + uint32_t group_id; /* Group identifier. */ + struct ofp_bucket buckets[0]; /* The length of the bucket array is inferred from the length field in the header. */ }; OFP_ASSERT(sizeof(struct ofp_group_mod) == 16); -/* Group commands */ -enum ofp_group_mod_command { - OFPGC_ADD = 0, /* New group. */ - OFPGC_MODIFY = 1, /* Modify all matching groups. */ - OFPGC_DELETE = 2, /* Delete all matching groups. */ -}; - -/* Group types. Values in the range [128, 255] are reserved for experimental -* use. */ +/* Group types. Values in the range [128, 255] are reserved for experimental + * use. */ enum ofp_group_type { - OFPGT_ALL = 0, /* All (multicast/broadcast) group. */ - OFPGT_SELECT = 1, /* Select group. */ + OFPGT_ALL = 0, /* All (multicast/broadcast) group. */ + OFPGT_SELECT = 1, /* Select group. */ OFPGT_INDIRECT = 2, /* Indirect group. */ - OFPGT_FF = 3, /* Fast failover group. */ + OFPGT_FF = 3, /* Fast failover group. */ }; +/* Special buffer-id to indicate 'no buffer' */ +#define OFP_NO_BUFFER 0xffffffff -/* Modify behavior of the physical port */ -struct ofp_port_mod { - struct ofp_header header; - uint32_t port_no; - uint8_t pad[4]; - 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_port struct. */ - uint8_t pad2[2]; /* Pad to 64 bits. */ - uint32_t config; /* Bitmap of OFPPC_* flags. */ - uint32_t mask; /* Bitmap of OFPPC_* flags to be changed. */ - uint32_t advertise; /* Bitmap of OFPPF_*. Zero all bits to prevent - any action taking place. */ - uint8_t pad3[4]; /* Pad to 64 bits. */ +/* Send packet (controller -> datapath). */ +struct ofp_packet_out { + struct ofp_header header; + uint32_t buffer_id; /* ID assigned by datapath (OFP_NO_BUFFER + if none). */ + uint32_t in_port; /* Packet's input port or OFPP_CONTROLLER. */ + uint16_t actions_len; /* Size of action array in bytes. */ + uint8_t pad[6]; + struct ofp_action_header actions[0]; /* Action list - 0 or more. */ + /* The variable size action list is optionally followed by packet data. + * This data is only present and meaningful if buffer_id == -1. + * uint8_t data[0]; Packet data. The length is inferred + from the length field in the header. */ }; -OFP_ASSERT(sizeof(struct ofp_port_mod) == 40); +OFP_ASSERT(sizeof(struct ofp_packet_out) == 24); -/* Common header for all meter bands */ -struct ofp_meter_band_header { - uint16_t type; /* One of OFPMBT_*. */ - uint16_t len; /* Length in bytes of this band. */ - uint32_t rate; /* Rate for this band. */ - uint32_t burst_size; /* Size of bursts. */ +/* Why is this packet being sent to the controller? */ +enum ofp_packet_in_reason { + OFPR_NO_MATCH = 0, /* No matching flow (table-miss flow entry). */ + OFPR_ACTION = 1, /* Action explicitly output to controller. */ + OFPR_INVALID_TTL = 2, /* Packet has invalid TTL */ }; -OFP_ASSERT(sizeof(struct ofp_meter_band_header) == 12); -/* Meter configuration. OFPT_METER_MOD. */ -struct ofp_meter_mod { +/* Packet received on port (datapath -> controller). */ +struct ofp_packet_in { struct ofp_header header; - uint16_t command; /* One of OFPMC_*. */ - uint16_t flags; /* One of OFPMF_*. */ - uint32_t meter_id; /* Meter instance. */ - struct ofp_meter_band_header bands[0]; /* The bands length is - inferred from the length field - in the header. */ + uint32_t buffer_id; /* ID assigned by datapath. */ + uint16_t total_len; /* Full length of frame. */ + uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ + uint8_t table_id; /* ID of the table that was looked up */ + uint64_t cookie; /* Cookie of the flow entry that was looked up. */ + struct ofp_match match; /* Packet metadata. Variable size. */ + /* The variable size and padded match is always followed by: + * - Exactly 2 all-zero padding bytes, then + * - An Ethernet frame whose length is inferred from header.length. + * The padding bytes preceding the Ethernet frame ensure that the IP + * header (if any) following the Ethernet header is 32-bit aligned. + */ + //uint8_t pad[2]; /* Align to 64 bit + 16 bit */ + //uint8_t data[0]; /* Ethernet frame */ }; -OFP_ASSERT(sizeof(struct ofp_meter_mod) == 16); +OFP_ASSERT(sizeof(struct ofp_packet_in) == 32); -/* Meter numbering. Flow meters can use any number up to OFPM_MAX. */ -enum ofp_meter { - /* Last usable meter. */ - OFPM_MAX = 0xffff0000, - /* Virtual meters. */ - OFPM_SLOWPATH = 0xfffffffd, - OFPM_CONTROLLER = 0xfffffffe, - OFPM_ALL = 0xffffffff, /* Meter for slow datapath, if any. */ - /* Meter for controller connection. */ - /* Represents all meters for stat requests - commands. */ +/* Why was this flow removed? */ +enum ofp_flow_removed_reason { + OFPRR_IDLE_TIMEOUT = 0, /* Flow idle time exceeded idle_timeout. */ + OFPRR_HARD_TIMEOUT = 1, /* Time exceeded hard_timeout. */ + OFPRR_DELETE = 2, /* Evicted by a DELETE flow mod. */ + OFPRR_GROUP_DELETE = 3, /* Group was removed. */ + OFPRR_METER_DELETE = 4, /* Meter was removed */ }; -/* Meter commands */ -enum ofp_meter_mod_command { - OFPMC_ADD, /* New meter. */ - OFPMC_MODIFY, /* Modify specified meter. */ - OFPMC_DELETE, /* Delete specified meter. */ -}; +/* Flow removed (datapath -> controller). */ +struct ofp_flow_removed { + struct ofp_header header; + uint64_t cookie; /* Opaque controller-issued identifier. */ -/* Meter configuration flags */ -enum ofp_meter_flags { - OFPMF_KBPS = 1 << 0, /* Rate value in kb/s (kilo-bit per second). */ - OFPMF_PKTPS = 1 << 1, /* Rate value in packet/sec. */ - OFPMF_BURST = 1 << 2, /* Do burst size. */ - OFPMF_STATS = 1 << 3, /* Collect statistics. */ + uint16_t priority; /* Priority level of flow entry. */ + uint8_t reason; /* One of OFPRR_*. */ + uint8_t table_id; /* ID of the table */ + + 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. */ + uint16_t hard_timeout; /* Hard timeout from original flow mod. */ + uint64_t packet_count; + uint64_t byte_count; + struct ofp_match match; /* Description of fields. Variable size. */ }; +OFP_ASSERT(sizeof(struct ofp_flow_removed) == 56); +/* Meter numbering. Flow meters can use any number up to OFPM_MAX. */ +enum ofp_meter { + /* Last usable meter. */ + OFPM_MAX = 0xffff0000, + + /* Virtual meters. */ + OFPM_SLOWPATH = 0xfffffffd, /* Meter for slow datapath. */ + OFPM_CONTROLLER = 0xfffffffe, /* Meter for controller connection. */ + OFPM_ALL = 0xffffffff, /* Represents all meters for stat requests + commands. */ +}; /* Meter band types */ enum ofp_meter_band_type { - OFPMBT_DROP = 1, /* Drop packet. */ - OFPMBT_DSCP_REMARK = 2, /* Remark DSCP in the IP header. */ - OFPMBT_EXPERIMENTER = 0xFFFF /* Experimenter meter band. */ + OFPMBT_DROP = 1, /* Drop packet. */ + OFPMBT_DSCP_REMARK = 2, /* Remark DSCP in the IP header. */ + OFPMBT_EXPERIMENTER = 0xFFFF /* Experimenter meter band. */ }; +/* Common header for all meter bands */ +struct ofp_meter_band_header { + uint16_t type; /* One of OFPMBT_*. */ + uint16_t len; /* Length in bytes of this band. */ + uint32_t rate; /* Rate for this band. */ + uint32_t burst_size; /* Size of bursts. */ +}; +OFP_ASSERT(sizeof(struct ofp_meter_band_header) == 12); + /* OFPMBT_DROP band - drop packets */ struct ofp_meter_band_drop { - uint16_t type; /* OFPMBT_DROP. */ - uint16_t len; /* Length in bytes of this band. */ - uint32_t rate; /* Rate for dropping packets. */ - uint32_t burst_size; /* Size of bursts. */ - uint8_t pad[4]; + uint16_t type; /* OFPMBT_DROP. */ + uint16_t len; /* Length in bytes of this band. */ + uint32_t rate; /* Rate for dropping packets. */ + uint32_t burst_size; /* Size of bursts. */ + uint8_t pad[4]; }; OFP_ASSERT(sizeof(struct ofp_meter_band_drop) == 16); /* OFPMBT_DSCP_REMARK band - Remark DSCP in the IP header */ struct ofp_meter_band_dscp_remark { - uint16_t type; /* OFPMBT_DSCP_REMARK. */ - uint16_t len; /* Length in bytes of this band. */ - uint32_t rate; /* Rate for remarking packets. */ - uint32_t burst_size; /* Size of bursts. */ - uint8_t prec_level; /* Number of precendence level to substract. */ - uint8_t pad[3]; + uint16_t type; /* OFPMBT_DSCP_REMARK. */ + uint16_t len; /* Length in bytes of this band. */ + uint32_t rate; /* Rate for remarking packets. */ + uint32_t burst_size; /* Size of bursts. */ + uint8_t prec_level; /* Number of drop precedence level to add. */ + uint8_t pad[3]; }; OFP_ASSERT(sizeof(struct ofp_meter_band_dscp_remark) == 16); -/* OFPMBT_EXPERIMENTER band - Write actions in action set */ +/* OFPMBT_EXPERIMENTER band - Experimenter type. + * The rest of the band is experimenter-defined. */ struct ofp_meter_band_experimenter { - uint16_t type; /* One of OFPMBT_*. */ - uint16_t len; /* Length in bytes of this band. */ - uint32_t rate; /* Rate for this band. */ - uint32_t burst_size; /* Size of bursts. */ - uint32_t experimenter; /* Experimenter ID which takes the same - form as in struct - ofp_experimenter_header. */ + uint16_t type; /* One of OFPMBT_*. */ + uint16_t len; /* Length in bytes of this band. */ + uint32_t rate; /* Rate for this band. */ + uint32_t burst_size; /* Size of bursts. */ + uint32_t experimenter; /* Experimenter ID which takes the same + form as in struct + ofp_experimenter_header. */ }; OFP_ASSERT(sizeof(struct ofp_meter_band_experimenter) == 16); +/* Meter commands */ +enum ofp_meter_mod_command { + OFPMC_ADD, /* New meter. */ + OFPMC_MODIFY, /* Modify specified meter. */ + OFPMC_DELETE, /* Delete specified meter. */ +}; -struct ofp_multipart_request { - struct ofp_header header; - uint16_t type; /* One of the OFPMP_* constants. */ - uint16_t flags; /* OFPMP_REQ_* flags (none yet defined). */ - uint8_t pad[4]; - uint8_t body[0]; /* Body of the request. */ +/* Meter configuration flags */ +enum ofp_meter_flags { + OFPMF_KBPS = 1 << 0, /* Rate value in kb/s (kilo-bit per second). */ + OFPMF_PKTPS = 1 << 1, /* Rate value in packet/sec. */ + OFPMF_BURST = 1 << 2, /* Do burst size. */ + OFPMF_STATS = 1 << 3, /* Collect statistics. */ +}; + +/* Meter configuration. OFPT_METER_MOD. */ +struct ofp_meter_mod { + struct ofp_header header; + uint16_t command; /* One of OFPMC_*. */ + uint16_t flags; /* Bitmap of OFPMF_* flags. */ + uint32_t meter_id; /* Meter instance. */ + struct ofp_meter_band_header bands[0]; /* The band list length is + inferred from the length field + in the header. */ +}; +OFP_ASSERT(sizeof(struct ofp_meter_mod) == 16); + +/* 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 = 0, /* Hello protocol failed. */ + OFPET_BAD_REQUEST = 1, /* Request was not understood. */ + OFPET_BAD_ACTION = 2, /* Error in action description. */ + OFPET_BAD_INSTRUCTION = 3, /* Error in instruction list. */ + OFPET_BAD_MATCH = 4, /* Error in match. */ + OFPET_FLOW_MOD_FAILED = 5, /* Problem modifying flow entry. */ + OFPET_GROUP_MOD_FAILED = 6, /* Problem modifying group entry. */ + OFPET_PORT_MOD_FAILED = 7, /* Port mod request failed. */ + OFPET_TABLE_MOD_FAILED = 8, /* Table mod request failed. */ + OFPET_QUEUE_OP_FAILED = 9, /* Queue operation failed. */ + OFPET_SWITCH_CONFIG_FAILED = 10, /* Switch config request failed. */ + OFPET_ROLE_REQUEST_FAILED = 11, /* Controller Role request failed. */ + OFPET_METER_MOD_FAILED = 12, /* Error in meter. */ + OFPET_TABLE_FEATURES_FAILED = 13, /* Setting table features failed. */ + OFPET_EXPERIMENTER = 0xffff /* Experimenter error messages. */ +}; + +/* 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 = 0, /* No compatible version. */ + OFPHFC_EPERM = 1, /* 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 = 0, /* ofp_header.version not supported. */ + OFPBRC_BAD_TYPE = 1, /* ofp_header.type not supported. */ + OFPBRC_BAD_MULTIPART = 2, /* ofp_multipart_request.type not supported. */ + OFPBRC_BAD_EXPERIMENTER = 3, /* Experimenter id not supported + * (in ofp_experimenter_header or + * ofp_multipart_request or + * ofp_multipart_reply). */ + OFPBRC_BAD_EXP_TYPE = 4, /* Experimenter type not supported. */ + OFPBRC_EPERM = 5, /* Permissions error. */ + OFPBRC_BAD_LEN = 6, /* Wrong request length for type. */ + OFPBRC_BUFFER_EMPTY = 7, /* Specified buffer has already been used. */ + OFPBRC_BUFFER_UNKNOWN = 8, /* Specified buffer does not exist. */ + OFPBRC_BAD_TABLE_ID = 9, /* Specified table-id invalid or does not + * exist. */ + OFPBRC_IS_SLAVE = 10, /* Denied because controller is slave. */ + OFPBRC_BAD_PORT = 11, /* Invalid port. */ + OFPBRC_BAD_PACKET = 12, /* Invalid packet in packet-out. */ + OFPBRC_MULTIPART_BUFFER_OVERFLOW = 13, /* ofp_multipart_request + overflowed the assigned buffer. */ +}; + +/* 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 = 0, /* Unknown or unsupported action type. */ + OFPBAC_BAD_LEN = 1, /* Length problem in actions. */ + OFPBAC_BAD_EXPERIMENTER = 2, /* Unknown experimenter id specified. */ + OFPBAC_BAD_EXP_TYPE = 3, /* Unknown action for experimenter id. */ + OFPBAC_BAD_OUT_PORT = 4, /* Problem validating output port. */ + OFPBAC_BAD_ARGUMENT = 5, /* Bad action argument. */ + OFPBAC_EPERM = 6, /* Permissions error. */ + OFPBAC_TOO_MANY = 7, /* Can't handle this many actions. */ + OFPBAC_BAD_QUEUE = 8, /* Problem validating output queue. */ + OFPBAC_BAD_OUT_GROUP = 9, /* Invalid group id in forward action. */ + OFPBAC_MATCH_INCONSISTENT = 10, /* Action can't apply for this match, + or Set-Field missing prerequisite. */ + OFPBAC_UNSUPPORTED_ORDER = 11, /* Action order is unsupported for the + action list in an Apply-Actions instruction */ + OFPBAC_BAD_TAG = 12, /* Actions uses an unsupported + tag/encap. */ + OFPBAC_BAD_SET_TYPE = 13, /* Unsupported type in SET_FIELD action. */ + OFPBAC_BAD_SET_LEN = 14, /* Length problem in SET_FIELD action. */ + OFPBAC_BAD_SET_ARGUMENT = 15, /* Bad argument in SET_FIELD action. */ +}; + +/* ofp_error_msg 'code' values for OFPET_BAD_INSTRUCTION. 'data' contains at least + * the first 64 bytes of the failed request. */ +enum ofp_bad_instruction_code { + OFPBIC_UNKNOWN_INST = 0, /* Unknown instruction. */ + OFPBIC_UNSUP_INST = 1, /* Switch or table does not support the + instruction. */ + OFPBIC_BAD_TABLE_ID = 2, /* Invalid Table-ID specified. */ + OFPBIC_UNSUP_METADATA = 3, /* Metadata value unsupported by datapath. */ + OFPBIC_UNSUP_METADATA_MASK = 4, /* Metadata mask value unsupported by + datapath. */ + OFPBIC_BAD_EXPERIMENTER = 5, /* Unknown experimenter id specified. */ + OFPBIC_BAD_EXP_TYPE = 6, /* Unknown instruction for experimenter id. */ + OFPBIC_BAD_LEN = 7, /* Length problem in instructions. */ + OFPBIC_EPERM = 8, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_BAD_MATCH. 'data' contains at least + * the first 64 bytes of the failed request. */ +enum ofp_bad_match_code { + OFPBMC_BAD_TYPE = 0, /* Unsupported match type specified by the + match */ + OFPBMC_BAD_LEN = 1, /* Length problem in match. */ + OFPBMC_BAD_TAG = 2, /* Match uses an unsupported tag/encap. */ + OFPBMC_BAD_DL_ADDR_MASK = 3, /* Unsupported datalink addr mask - switch + does not support arbitrary datalink + address mask. */ + OFPBMC_BAD_NW_ADDR_MASK = 4, /* Unsupported network addr mask - switch + does not support arbitrary network + address mask. */ + OFPBMC_BAD_WILDCARDS = 5, /* Unsupported combination of fields masked + or omitted in the match. */ + OFPBMC_BAD_FIELD = 6, /* Unsupported field type in the match. */ + OFPBMC_BAD_VALUE = 7, /* Unsupported value in a match field. */ + OFPBMC_BAD_MASK = 8, /* Unsupported mask specified in the match, + field is not dl-address or nw-address. */ + OFPBMC_BAD_PREREQ = 9, /* A prerequisite was not met. */ + OFPBMC_DUP_FIELD = 10, /* A field type was duplicated. */ + OFPBMC_EPERM = 11, /* Permissions error. */ +}; + +/* 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_UNKNOWN = 0, /* Unspecified error. */ + OFPFMFC_TABLE_FULL = 1, /* Flow not added because table was full. */ + OFPFMFC_BAD_TABLE_ID = 2, /* Table does not exist */ + OFPFMFC_OVERLAP = 3, /* Attempted to add overlapping flow with + CHECK_OVERLAP flag set. */ + OFPFMFC_EPERM = 4, /* Permissions error. */ + OFPFMFC_BAD_TIMEOUT = 5, /* Flow not added because of unsupported + idle/hard timeout. */ + OFPFMFC_BAD_COMMAND = 6, /* Unsupported or unknown command. */ + OFPFMFC_BAD_FLAGS = 7, /* Unsupported or unknown flags. */ +}; + +/* ofp_error_msg 'code' values for OFPET_GROUP_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_group_mod_failed_code { + OFPGMFC_GROUP_EXISTS = 0, /* Group not added because a group ADD + attempted to replace an + already-present group. */ + OFPGMFC_INVALID_GROUP = 1, /* Group not added because Group + specified is invalid. */ + OFPGMFC_WEIGHT_UNSUPPORTED = 2, /* Switch does not support unequal load + sharing with select groups. */ + OFPGMFC_OUT_OF_GROUPS = 3, /* The group table is full. */ + OFPGMFC_OUT_OF_BUCKETS = 4, /* The maximum number of action buckets + for a group has been exceeded. */ + OFPGMFC_CHAINING_UNSUPPORTED = 5, /* Switch does not support groups that + forward to groups. */ + OFPGMFC_WATCH_UNSUPPORTED = 6, /* This group cannot watch the watch_port + or watch_group specified. */ + OFPGMFC_LOOP = 7, /* Group entry would cause a loop. */ + OFPGMFC_UNKNOWN_GROUP = 8, /* Group not modified because a group + MODIFY attempted to modify a + non-existent group. */ + OFPGMFC_CHAINED_GROUP = 9, /* Group not deleted because another + group is forwarding to it. */ + OFPGMFC_BAD_TYPE = 10, /* Unsupported or unknown group type. */ + OFPGMFC_BAD_COMMAND = 11, /* Unsupported or unknown command. */ + OFPGMFC_BAD_BUCKET = 12, /* Error in bucket. */ + OFPGMFC_BAD_WATCH = 13, /* Error in watch port/group. */ + OFPGMFC_EPERM = 14, /* Permissions error. */ +}; + +/* 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 = 0, /* Specified port number does not exist. */ + OFPPMFC_BAD_HW_ADDR = 1, /* Specified hardware address does not + * match the port number. */ + OFPPMFC_BAD_CONFIG = 2, /* Specified config is invalid. */ + OFPPMFC_BAD_ADVERTISE = 3, /* Specified advertise is invalid. */ + OFPPMFC_EPERM = 4, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_TABLE_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_table_mod_failed_code { + OFPTMFC_BAD_TABLE = 0, /* Specified table does not exist. */ + OFPTMFC_BAD_CONFIG = 1, /* Specified config is invalid. */ + OFPTMFC_EPERM = 2, /* Permissions error. */ +}; + +/* 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 = 0, /* Invalid port (or port does not exist). */ + OFPQOFC_BAD_QUEUE = 1, /* Queue does not exist. */ + OFPQOFC_EPERM = 2, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_SWITCH_CONFIG_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_switch_config_failed_code { + OFPSCFC_BAD_FLAGS = 0, /* Specified flags is invalid. */ + OFPSCFC_BAD_LEN = 1, /* Specified len is invalid. */ + OFPSCFC_EPERM = 2, /* Permissions error. */ +}; + +/* ofp_error_msg 'code' values for OFPET_ROLE_REQUEST_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_role_request_failed_code { + OFPRRFC_STALE = 0, /* Stale Message: old generation_id. */ + OFPRRFC_UNSUP = 1, /* Controller role change unsupported. */ + OFPRRFC_BAD_ROLE = 2, /* Invalid role. */ +}; + +/* ofp_error_msg 'code' values for OFPET_METER_MOD_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_meter_mod_failed_code { + OFPMMFC_UNKNOWN = 0, /* Unspecified error. */ + OFPMMFC_METER_EXISTS = 1, /* Meter not added because a Meter ADD + * attempted to replace an existing Meter. */ + OFPMMFC_INVALID_METER = 2, /* Meter not added because Meter specified + * is invalid, + * or invalid meter in meter action. */ + OFPMMFC_UNKNOWN_METER = 3, /* Meter not modified because a Meter MODIFY + * attempted to modify a non-existent Meter, + * or bad meter in meter action. */ + OFPMMFC_BAD_COMMAND = 4, /* Unsupported or unknown command. */ + OFPMMFC_BAD_FLAGS = 5, /* Flag configuration unsupported. */ + OFPMMFC_BAD_RATE = 6, /* Rate unsupported. */ + OFPMMFC_BAD_BURST = 7, /* Burst size unsupported. */ + OFPMMFC_BAD_BAND = 8, /* Band unsupported. */ + OFPMMFC_BAD_BAND_VALUE = 9, /* Band value unsupported. */ + OFPMMFC_OUT_OF_METERS = 10, /* No more meters available. */ + OFPMMFC_OUT_OF_BANDS = 11, /* The maximum number of properties + * for a meter has been exceeded. */ }; -OFP_ASSERT(sizeof(struct ofp_multipart_request) == 16); -enum ofp_multipart_request_flags { - OFPMPF_REQ_MORE = 1 << 0 /* More requests to follow. */ +/* ofp_error_msg 'code' values for OFPET_TABLE_FEATURES_FAILED. 'data' contains + * at least the first 64 bytes of the failed request. */ +enum ofp_table_features_failed_code { + OFPTFFC_BAD_TABLE = 0, /* Specified table does not exist. */ + OFPTFFC_BAD_METADATA = 1, /* Invalid metadata mask. */ + OFPTFFC_BAD_TYPE = 2, /* Unknown property type. */ + OFPTFFC_BAD_LEN = 3, /* Length problem in properties. */ + OFPTFFC_BAD_ARGUMENT = 4, /* Unsupported property value. */ + OFPTFFC_EPERM = 5, /* Permissions error. */ }; -enum ofp_multipart_reply_flags { - OFPMPF_REPLY_MORE = 1 << 0 /* More replies to follow. */ +/* 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. No padding. */ }; +OFP_ASSERT(sizeof(struct ofp_error_msg) == 12); -struct ofp_multipart_reply { - struct ofp_header header; - uint16_t type; /* One of the OFPMP_* constants. */ - uint16_t flags; /* OFPMP_REPLY_* flags. */ - uint8_t pad[4]; - uint8_t body[0]; /* Body of the reply. */ +/* OFPET_EXPERIMENTER: Error message (datapath -> controller). */ +struct ofp_error_experimenter_msg { + struct ofp_header header; + + uint16_t type; /* OFPET_EXPERIMENTER. */ + uint16_t exp_type; /* Experimenter defined. */ + uint32_t experimenter; /* Experimenter ID which takes the same form + as in struct ofp_experimenter_header. */ + uint8_t data[0]; /* Variable-length data. Interpreted based + on the type and code. No padding. */ }; -OFP_ASSERT(sizeof(struct ofp_multipart_reply) == 16); +OFP_ASSERT(sizeof(struct ofp_error_experimenter_msg) == 16); -enum ofp_multipart_types { +enum ofp_multipart_type { /* Description of this OpenFlow switch. - * The request body is empty. - * The reply body is struct ofp_desc. */ + * The request body is empty. + * The reply body is struct ofp_desc. */ OFPMP_DESC = 0, + /* Individual flow statistics. - * The request body is struct ofp_flow_multipart_request. - * The reply body is an array of struct ofp_flow_stats. */ + * The request body is struct ofp_flow_stats_request. + * The reply body is an array of struct ofp_flow_stats. */ OFPMP_FLOW = 1, + /* Aggregate flow statistics. - * The request body is struct ofp_aggregate_stats_request. - * The reply body is struct ofp_aggregate_stats_reply. */ + * The request body is struct ofp_aggregate_stats_request. + * The reply body is struct ofp_aggregate_stats_reply. */ OFPMP_AGGREGATE = 2, + /* Flow table statistics. - * The request body is empty. - * The reply body is an array of struct ofp_table_stats. */ + * The request body is empty. + * The reply body is an array of struct ofp_table_stats. */ OFPMP_TABLE = 3, + /* Port statistics. - * The request body is struct ofp_port_stats_request. - * The reply body is an array of struct ofp_port_stats. */ + * The request body is struct ofp_port_stats_request. + * The reply body is an array of struct ofp_port_stats. */ OFPMP_PORT_STATS = 4, + /* Queue statistics for a port - * The request body is struct ofp_queue_stats_request. - * The reply body is an array of struct ofp_queue_stats */ + * The request body is struct ofp_queue_stats_request. + * The reply body is an array of struct ofp_queue_stats */ OFPMP_QUEUE = 5, + /* Group counter statistics. - * The request body is struct ofp_group_stats_request. - * The reply is an array of struct ofp_group_stats. */ + * The request body is struct ofp_group_stats_request. + * The reply is an array of struct ofp_group_stats. */ OFPMP_GROUP = 6, - /* Group description statistics. - * The request body is empty. - * The reply body is an array of struct ofp_group_desc_stats. */ + + /* Group description. + * The request body is empty. + * The reply body is an array of struct ofp_group_desc. */ OFPMP_GROUP_DESC = 7, + /* Group features. - * The request body is empty. - * The reply body is struct ofp_group_features_stats. */ + * The request body is empty. + * The reply body is struct ofp_group_features. */ OFPMP_GROUP_FEATURES = 8, + /* Meter statistics. * The request body is struct ofp_meter_multipart_requests. * The reply body is an array of struct ofp_meter_stats. */ OFPMP_METER = 9, + /* Meter configuration. - * The request body is struct ofp_meter_multipart_requests. - * The reply body is an array of struct ofp_meter_config. */ + * The request body is struct ofp_meter_multipart_requests. + * The reply body is an array of struct ofp_meter_config. */ OFPMP_METER_CONFIG = 10, + /* Meter features. - * The request body is empty. - * The reply body is struct ofp_meter_features. */ + * The request body is empty. + * The reply body is struct ofp_meter_features. */ OFPMP_METER_FEATURES = 11, + /* Table features. - * The request body is either empty or contains an array of - * struct ofp_table_features containing the controller’s - * desired view of the switch. If the switch is unable to - * set the specified view an error is returned. - * The reply body is an array of struct ofp_table_features. */ + * The request body is either empty or contains an array of + * struct ofp_table_features containing the controller's + * desired view of the switch. If the switch is unable to + * set the specified view an error is returned. + * The reply body is an array of struct ofp_table_features. */ OFPMP_TABLE_FEATURES = 12, + /* Port description. - * The request body is empty. - * The reply body is an array of struct ofp_port. */ + * The request body is empty. + * The reply body is an array of struct ofp_port. */ OFPMP_PORT_DESC = 13, + /* Experimenter extension. - * The request and reply bodies begin with - * struct ofp_experimenter_stats_header. - * The request and reply bodies are otherwise experimenter-defined. */ + * The request and reply bodies begin with + * struct ofp_experimenter_multipart_header. + * The request and reply bodies are otherwise experimenter-defined. */ OFPMP_EXPERIMENTER = 0xffff }; +/* Backward compatibility with 1.3.1 - avoid breaking the API. */ +#define ofp_multipart_types ofp_multipart_type + +enum ofp_multipart_request_flags { + OFPMPF_REQ_MORE = 1 << 0 /* More requests to follow. */ +}; + +struct ofp_multipart_request { + struct ofp_header header; + uint16_t type; /* One of the OFPMP_* constants. */ + uint16_t flags; /* OFPMPF_REQ_* flags. */ + uint8_t pad[4]; + uint8_t body[0]; /* Body of the request. 0 or more bytes. */ +}; +OFP_ASSERT(sizeof(struct ofp_multipart_request) == 16); + +enum ofp_multipart_reply_flags { + OFPMPF_REPLY_MORE = 1 << 0 /* More replies to follow. */ +}; + +struct ofp_multipart_reply { + struct ofp_header header; + uint16_t type; /* One of the OFPMP_* constants. */ + uint16_t flags; /* OFPMPF_REPLY_* flags. */ + uint8_t pad[4]; + uint8_t body[0]; /* Body of the reply. 0 or more bytes. */ +}; +OFP_ASSERT(sizeof(struct ofp_multipart_reply) == 16); + #define DESC_STR_LEN 256 #define SERIAL_NUM_LEN 32 -/* Body of reply to OFPMP_DESC request. Each entry is a NULL-terminated -* ASCII string. */ +/* Body of reply to OFPMP_DESC request. Each entry is a NULL-terminated + * ASCII string. */ struct ofp_desc { - 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. */ + 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) == 1056); /* Body for ofp_multipart_request of type OFPMP_FLOW. */ struct ofp_flow_stats_request { - uint8_t table_id; /* ID of table to read (from ofp_table_stats), - OFPTT_ALL for all tables. */ - uint8_t pad[3]; /* Align to 32 bits. */ - uint32_t out_port; /* Require matching entries to include this - as an output port. A value of OFPP_ANY - indicates no restriction. */ - uint32_t out_group; /* Require matching entries to include this - as an output group. A value of OFPG_ANY - indicates no restriction. */ - uint8_t pad2[4]; /* Align to 64 bits. */ - uint64_t cookie; /* Require matching entries to contain this - cookie value */ - uint64_t cookie_mask; /* Mask used to restrict the cookie bits that - must match. A value of 0 indicates - no restriction. */ - struct ofp_match match; /* Fields to match. Variable size. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats), + OFPTT_ALL for all tables. */ + uint8_t pad[3]; /* Align to 32 bits. */ + uint32_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_ANY + indicates no restriction. */ + uint32_t out_group; /* Require matching entries to include this + as an output group. A value of OFPG_ANY + indicates no restriction. */ + uint8_t pad2[4]; /* Align to 64 bits. */ + uint64_t cookie; /* Require matching entries to contain this + cookie value */ + uint64_t cookie_mask; /* Mask used to restrict the cookie bits that + must match. A value of 0 indicates + no restriction. */ + struct ofp_match match; /* Fields to match. Variable size. */ }; OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 40); /* Body of reply to OFPMP_FLOW request. */ struct ofp_flow_stats { +<<<<<<< HEAD uint16_t length; /* Length of this entry. */ uint8_t table_id; /* ID of table flow came from. */ uint8_t pad; @@ -1007,748 +1850,513 @@ struct ofp_flow_stats { uint64_t byte_count; /* Number of bytes in flow. */ struct ofp_match match; /* Description of fields. Variable size. */ //struct ofp_instruction instructions[0]; /* Instruction set. */ +======= + uint16_t length; /* Length of this entry. */ + uint8_t table_id; /* ID of table flow came from. */ + uint8_t pad; + 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. */ + uint16_t idle_timeout; /* Number of seconds idle before expiration. */ + uint16_t hard_timeout; /* Number of seconds before expiration. */ + uint16_t flags; /* Bitmap of OFPFF_* flags. */ + uint8_t pad2[4]; /* 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_match match; /* Description of fields. Variable size. */ + /* The variable size and padded match is always followed by instructions. */ + //struct ofp_instruction instructions[0]; /* Instruction set - 0 or more. */ +>>>>>>> e309316... Update openflow.h to OpenFlow 1.3.5 }; OFP_ASSERT(sizeof(struct ofp_flow_stats) == 56); /* Body for ofp_multipart_request of type OFPMP_AGGREGATE. */ struct ofp_aggregate_stats_request { - uint8_t table_id; /* ID of table to read (from ofp_table_stats) - OFPTT_ALL for all tables. */ - uint8_t pad[3]; /* Align to 32 bits. */ - uint32_t out_port; /* Require matching entries to include this - as an output port. A value of OFPP_ANY - indicates no restriction. */ - uint32_t out_group; /* Require matching entries to include this - as an output group. A value of OFPG_ANY - indicates no restriction. */ - uint8_t pad2[4]; /* Align to 64 bits. */ - uint64_t cookie; /* Require matching entries to contain this - cookie value */ - uint64_t cookie_mask; /* Mask used to restrict the cookie bits that - must match. A value of 0 indicates - no restriction. */ - struct ofp_match match; /* Fields to match. Variable size. */ + uint8_t table_id; /* ID of table to read (from ofp_table_stats) + OFPTT_ALL for all tables. */ + uint8_t pad[3]; /* Align to 32 bits. */ + uint32_t out_port; /* Require matching entries to include this + as an output port. A value of OFPP_ANY + indicates no restriction. */ + uint32_t out_group; /* Require matching entries to include this + as an output group. A value of OFPG_ANY + indicates no restriction. */ + uint8_t pad2[4]; /* Align to 64 bits. */ + uint64_t cookie; /* Require matching entries to contain this + cookie value */ + uint64_t cookie_mask; /* Mask used to restrict the cookie bits that + must match. A value of 0 indicates + no restriction. */ + struct ofp_match match; /* Fields to match. Variable size. */ }; OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 40); /* Body of reply to OFPMP_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. */ + 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 OFPMP_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. */ - 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) == 24); - -struct ofp_table_feature_prop_header{ - uint16_t type; /* One of OFPTFPT_NEXT_TABLES, - OFPTFPT_NEXT_TABLES_MISS. */ - uint16_t length; /* Length in bytes of this property. */ -}; -OFP_ASSERT(sizeof(struct ofp_table_feature_prop_header) == 4); - -/* Body for ofp_multipart_request of type OFPMP_TABLE_FEATURES./ -* Body of reply to OFPMP_TABLE_FEATURES request. */ -struct ofp_table_features { - uint16_t length; /* Length is padded to 64 bits. */ - uint8_t table_id; /* Identifier of table. Lower numbered tables - are consulted first. */ - uint8_t pad[5]; /* Align to 64-bits. */ - char name[OFP_MAX_TABLE_NAME_LEN]; - uint64_t metadata_match; /* Bits of metadata table can match. */ - uint64_t metadata_write; /* Bits of metadata table can write. */ - uint32_t config; /* Bitmap of OFPTC_* values */ - uint32_t max_entries; /* Max number of entries supported. */ - /* Table Feature Property list */ - struct ofp_table_feature_prop_header properties[0]; -}; -OFP_ASSERT(sizeof(struct ofp_table_features) == 64); - /* Table Feature property types. -* Low order bit cleared indicates a property for a regular Flow Entry. -* Low order bit set indicates a property for the Table-Miss Flow Entry. -*/ + * Low order bit cleared indicates a property for a regular Flow Entry. + * Low order bit set indicates a property for the Table-Miss Flow Entry. + */ enum ofp_table_feature_prop_type { - OFPTFPT_INSTRUCTIONS = 0, /* Instructions property. */ - OFPTFPT_INSTRUCTIONS_MISS = 1, /* Instructions for table-miss. */ - OFPTFPT_NEXT_TABLES = 2, /* Next Table property. */ - OFPTFPT_NEXT_TABLES_MISS = 3, /* Next Table for table-miss. */ - OFPTFPT_WRITE_ACTIONS = 4, /* Write Actions property. */ - OFPTFPT_WRITE_ACTIONS_MISS = 5, /* Write Actions for table-miss. */ - OFPTFPT_APPLY_ACTIONS = 6, /* Apply Actions property. */ - OFPTFPT_APPLY_ACTIONS_MISS = 7, /* Apply Actions for table-miss. */ - OFPTFPT_MATCH = 8, /* Match property. */ - OFPTFPT_WILDCARDS = 10, /* Wildcards property. */ - OFPTFPT_WRITE_SETFIELD = 12, /* Write Set-Field property. */ - OFPTFPT_WRITE_SETFIELD_MISS = 13, /* Write Set-Field for table-miss. */ - OFPTFPT_APPLY_SETFIELD = 14, /* Apply Set-Field property. */ - OFPTFPT_APPLY_SETFIELD_MISS = 15, /* Apply Set-Field for table-miss. */ - OFPTFPT_EXPERIMENTER = 0xFFFE, /* Experimenter property. */ - OFPTFPT_EXPERIMENTER_MISS = 0xFFFF, /* Experimenter for table-miss. */ + OFPTFPT_INSTRUCTIONS = 0, /* Instructions property. */ + OFPTFPT_INSTRUCTIONS_MISS = 1, /* Instructions for table-miss. */ + OFPTFPT_NEXT_TABLES = 2, /* Next Table property. */ + OFPTFPT_NEXT_TABLES_MISS = 3, /* Next Table for table-miss. */ + OFPTFPT_WRITE_ACTIONS = 4, /* Write Actions property. */ + OFPTFPT_WRITE_ACTIONS_MISS = 5, /* Write Actions for table-miss. */ + OFPTFPT_APPLY_ACTIONS = 6, /* Apply Actions property. */ + OFPTFPT_APPLY_ACTIONS_MISS = 7, /* Apply Actions for table-miss. */ + OFPTFPT_MATCH = 8, /* Match property. */ + OFPTFPT_WILDCARDS = 10, /* Wildcards property. */ + OFPTFPT_WRITE_SETFIELD = 12, /* Write Set-Field property. */ + OFPTFPT_WRITE_SETFIELD_MISS = 13, /* Write Set-Field for table-miss. */ + OFPTFPT_APPLY_SETFIELD = 14, /* Apply Set-Field property. */ + OFPTFPT_APPLY_SETFIELD_MISS = 15, /* Apply Set-Field for table-miss. */ + OFPTFPT_EXPERIMENTER = 0xFFFE, /* Experimenter property. */ + OFPTFPT_EXPERIMENTER_MISS = 0xFFFF, /* Experimenter for table-miss. */ +}; + +/* Common header for all Table Feature Properties */ +struct ofp_table_feature_prop_header { + uint16_t type; /* One of OFPTFPT_*. */ + uint16_t length; /* Length in bytes of this property. */ }; +OFP_ASSERT(sizeof(struct ofp_table_feature_prop_header) == 4); /* Instructions property */ struct ofp_table_feature_prop_instructions { - uint16_t type; /* One of OFPTFPT_INSTRUCTIONS, - OFPTFPT_INSTRUCTIONS_MISS. */ - uint16_t length; /* Length in bytes of this property. */ + uint16_t type; /* One of OFPTFPT_INSTRUCTIONS, + OFPTFPT_INSTRUCTIONS_MISS. */ + uint16_t length; /* Length in bytes of this property. */ /* Followed by: - * - - Exactly (length - 4) bytes containing the instruction ids, then - * - - Exactly (length + 7)/8*8 - (length) (between 0 and 7) - * - bytes of all-zero bytes */ - struct ofp_instruction instruction_ids[0]; /* List of instructions */ + * - Exactly (length - 4) bytes containing the instruction ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + struct ofp_instruction instruction_ids[0]; /* List of instructions */ }; OFP_ASSERT(sizeof(struct ofp_table_feature_prop_instructions) == 4); - +/* Next Tables property */ struct ofp_table_feature_prop_next_tables { - uint16_t type; /* One of OFPTFPT_NEXT_TABLES, - OFPTFPT_NEXT_TABLES_MISS. */ - uint16_t length; /* Length in bytes of this property. */ + uint16_t type; /* One of OFPTFPT_NEXT_TABLES, + OFPTFPT_NEXT_TABLES_MISS. */ + uint16_t length; /* Length in bytes of this property. */ /* Followed by: - * - - Exactly (length - 4) bytes containing the table_ids, then - * - - Exactly (length + 7)/8*8 - (length) (between 0 and 7) - * - bytes of all-zero bytes */ - uint8_t next_table_ids[0]; + * - Exactly (length - 4) bytes containing the table_ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + uint8_t next_table_ids[0]; /* List of table ids. */ }; OFP_ASSERT(sizeof(struct ofp_table_feature_prop_next_tables) == 4); /* Actions property */ struct ofp_table_feature_prop_actions { - uint16_t type; /* One of OFPTFPT_WRITE_ACTIONS, - OFPTFPT_WRITE_ACTIONS_MISS, - OFPTFPT_APPLY_ACTIONS, - OFPTFPT_APPLY_ACTIONS_MISS. */ - - uint16_t length; /* Length in bytes of this property. */ + uint16_t type; /* One of OFPTFPT_WRITE_ACTIONS, + OFPTFPT_WRITE_ACTIONS_MISS, + OFPTFPT_APPLY_ACTIONS, + OFPTFPT_APPLY_ACTIONS_MISS. */ + uint16_t length; /* Length in bytes of this property. */ /* Followed by: - * - - Exactly (length - 4) bytes containing the action_ids, then - * - - Exactly (length + 7)/8*8 - (length) (between 0 and 7) - * - bytes of all-zero bytes */ - struct ofp_action_header action_ids[0];/* List of actions */ + * - Exactly (length - 4) bytes containing the action_ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + struct ofp_action_header action_ids[0]; /* List of actions */ }; OFP_ASSERT(sizeof(struct ofp_table_feature_prop_actions) == 4); /* Match, Wildcard or Set-Field property */ struct ofp_table_feature_prop_oxm { - uint16_t type; /* One of OFPTFPT_MATCH, - OFPTFPT_WILDCARDS, - OFPTFPT_WRITE_SETFIELD, - OFPTFPT_WRITE_SETFIELD_MISS, - OFPTFPT_APPLY_SETFIELD, - OFPTFPT_APPLY_SETFIELD_MISS. */ - - uint16_t length; /* Length in bytes of this property. */ + uint16_t type; /* One of OFPTFPT_MATCH, + OFPTFPT_WILDCARDS, + OFPTFPT_WRITE_SETFIELD, + OFPTFPT_WRITE_SETFIELD_MISS, + OFPTFPT_APPLY_SETFIELD, + OFPTFPT_APPLY_SETFIELD_MISS. */ + uint16_t length; /* Length in bytes of this property. */ /* Followed by: - * - - Exactly (length - 4) bytes containing the oxm_ids, then - * - - Exactly (length + 7)/8*8 - (length) (between 0 and 7) - * - bytes of all-zero bytes */ - uint32_t oxm_ids[0]; /* Array of OXM headers */ + * - Exactly (length - 4) bytes containing the oxm_ids, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + uint32_t oxm_ids[0]; /* Array of OXM headers */ }; OFP_ASSERT(sizeof(struct ofp_table_feature_prop_oxm) == 4); +/* Experimenter table feature property */ +struct ofp_table_feature_prop_experimenter { + uint16_t type; /* One of OFPTFPT_EXPERIMENTER, + OFPTFPT_EXPERIMENTER_MISS. */ + uint16_t length; /* Length in bytes of this property. */ + uint32_t experimenter; /* Experimenter ID which takes the same + form as in struct + ofp_experimenter_header. */ + uint32_t exp_type; /* Experimenter defined. */ + /* Followed by: + * - Exactly (length - 12) bytes containing the experimenter data, then + * - Exactly (length + 7)/8*8 - (length) (between 0 and 7) + * bytes of all-zero bytes */ + uint32_t experimenter_data[0]; +}; +OFP_ASSERT(sizeof(struct ofp_table_feature_prop_experimenter) == 12); -/* Body for ofp_multipart_request of type OFPMP_PORT_STATS. */ -struct ofp_port_stats_request { - uint32_t port_no; /* OFPMP_PORT_STATS message must request statistics - * either for a single port (specified in - * port_no) or for all ports (if port_no == - * OFPP_ANY). */ - uint8_t pad[4]; +/* Body for ofp_multipart_request of type OFPMP_TABLE_FEATURES./ + * Body of reply to OFPMP_TABLE_FEATURES request. */ +struct ofp_table_features { + uint16_t length; /* Length is padded to 64 bits. */ + uint8_t table_id; /* Identifier of table. Lower numbered tables + are consulted first. */ + uint8_t pad[5]; /* Align to 64-bits. */ + char name[OFP_MAX_TABLE_NAME_LEN]; + uint64_t metadata_match; /* Bits of metadata table can match. */ + uint64_t metadata_write; /* Bits of metadata table can write. */ + uint32_t config; /* Bitmap of OFPTC_* values */ + uint32_t max_entries; /* Max number of entries supported. */ + + /* Table Feature Property list */ + struct ofp_table_feature_prop_header properties[0]; /* List of properties */ }; -OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); +OFP_ASSERT(sizeof(struct ofp_table_features) == 64); -/* Body of reply to OFPMP_PORT_STATS request. If a counter is unsupported, set -* the field to all ones. */ -struct ofp_port_stats { - uint32_t port_no; - uint8_t pad[4]; /* 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. */ - uint32_t duration_sec; /* Time port has been alive in seconds. */ - uint32_t duration_nsec; /* Time port has been alive in nanoseconds beyond - duration_sec. */ +/* Body of reply to OFPMP_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. */ + 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_port_stats) == 112); +OFP_ASSERT(sizeof(struct ofp_table_stats) == 24); -struct ofp_queue_stats_request { - uint32_t port_no; /* All ports if OFPP_ANY. */ - uint32_t queue_id; /* All queues if OFPQ_ALL. */ +/* Body for ofp_multipart_request of type OFPMP_PORT. */ +struct ofp_port_stats_request { + uint32_t port_no; /* OFPMP_PORT message must request statistics + * either for a single port (specified in + * port_no) or for all ports (if port_no == + * OFPP_ANY). */ + uint8_t pad[4]; }; -OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); +OFP_ASSERT(sizeof(struct ofp_port_stats_request) == 8); -struct ofp_queue_stats { - uint32_t port_no; - 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. */ - uint32_t duration_sec; /* Time queue has been alive in seconds. */ - uint32_t duration_nsec; /* Time queue has been alive in nanoseconds beyond +/* Body of reply to OFPMP_PORT request. If a counter is unsupported, set + * the field to all ones. */ +struct ofp_port_stats { + uint32_t port_no; + uint8_t pad[4]; /* 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. */ + uint32_t duration_sec; /* Time port has been alive in seconds. */ + uint32_t duration_nsec; /* Time port has been alive in nanoseconds beyond duration_sec. */ }; -OFP_ASSERT(sizeof(struct ofp_queue_stats) == 40); +OFP_ASSERT(sizeof(struct ofp_port_stats) == 112); /* Body of OFPMP_GROUP request. */ struct ofp_group_stats_request { - uint32_t group_id; /* All groups if OFPG_ALL. */ - uint8_t pad[4]; /* Align to 64 bits. */ + uint32_t group_id; /* All groups if OFPG_ALL. */ + uint8_t pad[4]; /* Align to 64 bits. */ }; OFP_ASSERT(sizeof(struct ofp_group_stats_request) == 8); /* Used in group stats replies. */ struct ofp_bucket_counter { - uint64_t packet_count; /* Number of packets processed by bucket. */ - uint64_t byte_count; /* Number of bytes processed by bucket. */ + uint64_t packet_count; /* Number of packets processed by bucket. */ + uint64_t byte_count; /* Number of bytes processed by bucket. */ }; OFP_ASSERT(sizeof(struct ofp_bucket_counter) == 16); /* Body of reply to OFPMP_GROUP request. */ struct ofp_group_stats { - uint16_t length; /* Length of this entry. */ - uint8_t pad[2]; /* Align to 64 bits. */ - uint32_t group_id; /* Group identifier. */ - uint32_t ref_count; /* Number of flows or groups that directly forward - to this group. */ - uint8_t pad2[4]; /* Align to 64 bits. */ - uint64_t packet_count; /* Number of packets processed by group. */ - uint64_t byte_count; /* Number of bytes processed by group. */ - uint32_t duration_sec; /* Time group has been alive in seconds. */ - uint32_t duration_nsec; /* Time group has been alive in nanoseconds beyond + uint16_t length; /* Length of this entry. */ + uint8_t pad[2]; /* Align to 64 bits. */ + uint32_t group_id; /* Group identifier. */ + uint32_t ref_count; /* Number of flows or groups that directly forward + to this group. */ + uint8_t pad2[4]; /* Align to 64 bits. */ + uint64_t packet_count; /* Number of packets processed by group. */ + uint64_t byte_count; /* Number of bytes processed by group. */ + uint32_t duration_sec; /* Time group has been alive in seconds. */ + uint32_t duration_nsec; /* Time group has been alive in nanoseconds beyond duration_sec. */ - struct ofp_bucket_counter bucket_stats[0]; - + struct ofp_bucket_counter bucket_stats[0]; /* One counter set per bucket. */ }; OFP_ASSERT(sizeof(struct ofp_group_stats) == 40); /* Body of reply to OFPMP_GROUP_DESC request. */ -struct ofp_group_desc_stats { - uint16_t length; /* Length of this entry. */ - uint8_t type; /* One of OFPGT_*. */ - uint8_t pad; /* Pad to 64 bits. */ - uint32_t group_id; /* Group identifier. */ - struct ofp_bucket buckets[0]; +struct ofp_group_desc { + uint16_t length; /* Length of this entry. */ + uint8_t type; /* One of OFPGT_*. */ + uint8_t pad; /* Pad to 64 bits. */ + uint32_t group_id; /* Group identifier. */ + struct ofp_bucket buckets[0]; /* List of buckets - 0 or more. */ }; -OFP_ASSERT(sizeof(struct ofp_group_desc_stats) == 8); +OFP_ASSERT(sizeof(struct ofp_group_desc) == 8); -/* Body of reply to OFPMP_GROUP_FEATURES request. Group features. */ -struct ofp_group_features_stats { - uint32_t types; /* Bitmap of OFPGT_* values supported. */ - uint32_t capabilities; /* Bitmap of OFPGFC_* capability supported. */ - uint32_t max_groups[4]; /* Maximum number of groups for each type. */ - uint32_t actions[4]; /* Bitmaps of OFPAT_* that are supported. */ -}; -OFP_ASSERT(sizeof(struct ofp_group_features_stats) == 40); +/* Backward compatibility with 1.3.1 - avoid breaking the API. */ +#define ofp_group_desc_stats ofp_group_desc /* Group configuration flags */ enum ofp_group_capabilities { - OFPGFC_SELECT_WEIGHT = 1 << 0, /* Support weight for select groups */ - OFPGFC_SELECT_LIVENESS = 1 << 1, /* Support liveness for select groups */ - OFPGFC_CHAINING = 1 << 2, /* Support chaining groups */ - OFPGFC_CHAINING_CHECKS = 1 << 3, /* Check chaining for loops and delete */ + OFPGFC_SELECT_WEIGHT = 1 << 0, /* Support weight for select groups */ + OFPGFC_SELECT_LIVENESS = 1 << 1, /* Support liveness for select groups */ + OFPGFC_CHAINING = 1 << 2, /* Support chaining groups */ + OFPGFC_CHAINING_CHECKS = 1 << 3, /* Check chaining for loops and delete */ }; +/* Body of reply to OFPMP_GROUP_FEATURES request. Group features. */ +struct ofp_group_features { + uint32_t types; /* Bitmap of (1 << OFPGT_*) values supported. */ + uint32_t capabilities; /* Bitmap of OFPGFC_* capability supported. */ + uint32_t max_groups[4]; /* Maximum number of groups for each type. */ + uint32_t actions[4]; /* Bitmaps of (1 << OFPAT_*) values supported. */ +}; +OFP_ASSERT(sizeof(struct ofp_group_features) == 40); + /* Body of OFPMP_METER and OFPMP_METER_CONFIG requests. */ struct ofp_meter_multipart_request { - uint32_t meter_id; /* Meter instance, or OFPM_ALL. */ - uint8_t pad[4]; /* Align to 64 bits. */ + uint32_t meter_id; /* Meter instance, or OFPM_ALL. */ + uint8_t pad[4]; /* Align to 64 bits. */ }; OFP_ASSERT(sizeof(struct ofp_meter_multipart_request) == 8); /* Statistics for each meter band */ struct ofp_meter_band_stats { - uint64_t packet_band_count; /* Number of packets in band. */ - uint64_t byte_band_count; /* Number of bytes in band. */ + uint64_t packet_band_count; /* Number of packets in band. */ + uint64_t byte_band_count; /* Number of bytes in band. */ }; OFP_ASSERT(sizeof(struct ofp_meter_band_stats) == 16); /* Body of reply to OFPMP_METER request. Meter statistics. */ struct ofp_meter_stats { - uint32_t meter_id; /* Meter instance. */ - uint16_t len; /* Length in bytes of this stats. */ - uint8_t pad[6]; - uint32_t flow_count; /* Number of flows bound to meter. */ - uint64_t packet_in_count; /* Number of packets in input. */ - uint64_t byte_in_count; /* Number of bytes in input. */ - uint32_t duration_sec; /* Time meter has been alive in seconds. */ - uint32_t duration_nsec; /* Time meter has been alive in nanoseconds beyond - duration_sec. */ + uint32_t meter_id; /* Meter instance. */ + uint16_t len; /* Length in bytes of this stats. */ + uint8_t pad[6]; + uint32_t flow_count; /* Number of flows bound to meter. */ + uint64_t packet_in_count; /* Number of packets in input. */ + uint64_t byte_in_count; /* Number of bytes in input. */ + uint32_t duration_sec; /* Time meter has been alive in seconds. */ + uint32_t duration_nsec; /* Time meter has been alive in nanoseconds beyond + duration_sec. */ struct ofp_meter_band_stats band_stats[0]; /* The band_stats length is - inferred from the length field. */ + inferred from the length field. */ }; OFP_ASSERT(sizeof(struct ofp_meter_stats) == 40); /* Body of reply to OFPMP_METER_CONFIG request. Meter configuration. */ struct ofp_meter_config { - uint16_t length; /* Length of this entry. */ - uint16_t flags; /* All OFPMC_* that apply. */ - uint32_t meter_id; /* Meter instance. */ + uint16_t length; /* Length of this entry. */ + uint16_t flags; /* All OFPMF_* that apply. */ + uint32_t meter_id; /* Meter instance. */ struct ofp_meter_band_header bands[0]; /* The bands length is - inferred from the length field. */ + inferred from the length field. */ }; OFP_ASSERT(sizeof(struct ofp_meter_config) == 8); /* Body of reply to OFPMP_METER_FEATURES request. Meter features. */ struct ofp_meter_features { - uint32_t max_meter; /* Maximum number of meters. */ - uint32_t band_types; /* Bitmaps of OFPMBT_* values supported. */ - uint32_t capabilities; /* Bitmaps of "ofp_meter_flags". */ - uint8_t max_bands; /* Maximum bands per meters */ - uint8_t max_color; /* Maximum color value */ - uint8_t pad[2]; + uint32_t max_meter; /* Maximum number of meters. */ + uint32_t band_types; /* Bitmaps of (1 << OFPMBT_*) values supported. */ + uint32_t capabilities; /* Bitmaps of "ofp_meter_flags". */ + uint8_t max_bands; /* Maximum bands per meters */ + uint8_t max_color; /* Maximum color value */ + uint8_t pad[2]; }; OFP_ASSERT(sizeof(struct ofp_meter_features) == 16); - /* Body for ofp_multipart_request/reply of type OFPMP_EXPERIMENTER. */ -struct ofp_experimenter_stats_header { - uint32_t experimenter; /* Experimenter ID which takes the same form - as in struct ofp_experimenter_header. */ - uint32_t exp_type; /* Experimenter defined. */ - /* Experimenter-defined arbitrary additional data. */ -}; -OFP_ASSERT(sizeof(struct ofp_experimenter_stats_header) == 8); - -/* Query for port queue configuration. */ -struct ofp_queue_get_config_request { - struct ofp_header header; - uint32_t port; /* Port to be queried. Should refer - to a valid physical port (i.e. < OFPP_MAX), - or OFPP_ANY to request all configured - queues.*/ - uint8_t pad[4]; -}; -OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 16); - -/* Queue configuration for a given port. */ -struct ofp_queue_get_config_reply { - struct ofp_header header; - uint32_t port; - uint8_t pad[4]; - struct ofp_packet_queue queues[0]; /* List of configured queues. */ -}; -OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); - -/* Send packet (controller -> datapath). */ -struct ofp_packet_out { - struct ofp_header header; - uint32_t buffer_id; /* ID assigned by datapath (OFP_NO_BUFFER - if none). */ - uint32_t in_port; /* Packet’s input port or OFPP_CONTROLLER. */ - uint16_t actions_len; /* Size of action array in bytes. */ - uint8_t pad[6]; - struct ofp_action_header actions[0]; /* Action list. */ - /* 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) == 24); - -/* Role request and reply message. */ -struct ofp_role_request { - struct ofp_header header; /* Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. */ - uint32_t role; /* One of NX_ROLE_*. */ - uint8_t pad[4]; /* Align to 64 bits. */ - uint64_t generation_id; /* Master Election Generation Id */ -}; -OFP_ASSERT(sizeof(struct ofp_role_request) == 24); - -/* Controller roles. */ -enum ofp_controller_role { - OFPCR_ROLE_NOCHANGE = 0, /* Don’t change current role. */ - OFPCR_ROLE_EQUAL = 1, /* Default role, full access. */ - OFPCR_ROLE_MASTER = 2, /* Full access, at most one master. */ - OFPCR_ROLE_SLAVE = 3, /* Read-only access. */ -}; - -/* Asynchronous message configuration. */ -struct ofp_async_config { - struct ofp_header header; /* OFPT_GET_ASYNC_REPLY or OFPT_SET_ASYNC. */ - uint32_t packet_in_mask[2]; /* Bitmasks of OFPR_* values. */ - uint32_t port_status_mask[2]; /* Bitmasks of OFPPR_* values. */ - uint32_t flow_removed_mask[2];/* Bitmasks of OFPRR_* values. */ +struct ofp_experimenter_multipart_header { + uint32_t experimenter; /* Experimenter ID which takes the same form + as in struct ofp_experimenter_header. */ + uint32_t exp_type; /* Experimenter defined. */ + /* Experimenter-defined arbitrary additional data. */ }; -OFP_ASSERT(sizeof(struct ofp_async_config) == 32); - - +OFP_ASSERT(sizeof(struct ofp_experimenter_multipart_header) == 8); -#define OFP_NO_BUFFER 0xffffffff - -/* 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. */ - uint8_t reason; /* Reason packet is being sent (one of OFPR_*) */ - uint8_t table_id; /* ID of the table that was looked up */ - uint64_t cookie; /* Cookie of the flow entry that was looked up. */ - struct ofp_match match; /* Packet metadata. Variable size. */ - /* Followed by: - * -Exactly 2 all-zero padding bytes,then - * -An Ethernetframe whose length is inferred from header.length. - * The padding bytes preceding the Ethernet frame ensure that the IP - * header (if any) following the Ethernet header is 32-bit aligned. - */ - //uint8_t pad[2]; /* Align to 64 bit + 16 bit */ - //uint8_t data[0]; /* Ethernet frame */ +/* Experimenter extension. */ +struct ofp_experimenter_header { + struct ofp_header header; /* Type OFPT_EXPERIMENTER. */ + uint32_t experimenter; /* Experimenter ID: + * - MSB 0: low-order bytes are IEEE OUI. + * - MSB != 0: defined by ONF. */ + uint32_t exp_type; /* Experimenter defined. */ + /* Experimenter-defined arbitrary additional data. */ }; -OFP_ASSERT(sizeof(struct ofp_packet_in) == 32); +OFP_ASSERT(sizeof(struct ofp_experimenter_header) == 16); -/* Why is this packet being sent to the controller? */ -enum ofp_packet_in_reason { - OFPR_NO_MATCH = 0, /* No matching flow. */ - OFPR_ACTION = 1, /* Action explicitly output to controller. */ - OFPR_INVALID_TTL = 2, /* Packet has invalid TTL */ -}; +/* All ones is used to indicate all queues in a port (for stats retrieval). */ +#define OFPQ_ALL 0xffffffff -/* Flow removed (datapath -> controller). */ -struct ofp_flow_removed { - struct ofp_header header; - uint64_t cookie; /* Opaque controller-issued identifier. */ - uint16_t priority; /* Priority level of flow entry. */ - uint8_t reason; /* One of OFPRR_*. */ - uint8_t table_id; /* ID of the table */ - 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. */ - uint16_t hard_timeout; /* Hard timeout from original flow mod. */ - uint64_t packet_count; - uint64_t byte_count; - struct ofp_match match; /* Description of fields. Variable size. */ -}; -OFP_ASSERT(sizeof(struct ofp_flow_removed) == 56); +/* Min rate > 1000 means not configured. */ +#define OFPQ_MIN_RATE_UNCFG 0xffff -/* Why was this flow removed? */ -enum ofp_flow_removed_reason { - OFPRR_IDLE_TIMEOUT = 0, /* Flow idle time exceeded idle_timeout. */ - OFPRR_HARD_TIMEOUT = 1, /* Time exceeded hard_timeout. */ - OFPRR_DELETE = 2, /* Evicted by a DELETE flow mod. */ - OFPRR_GROUP_DELETE = 3, /* Group was removed. */ - OFPRR_METER_DELETE = 4, /* Meter was removed. */ -}; +/* Max rate > 1000 means not configured. */ +#define OFPQ_MAX_RATE_UNCFG 0xffff -/* 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_port desc; +enum ofp_queue_properties { + OFPQT_MIN_RATE = 1, /* Minimum datarate guaranteed. */ + OFPQT_MAX_RATE = 2, /* Maximum datarate. */ + OFPQT_EXPERIMENTER = 0xffff /* Experimenter defined property. */ }; -OFP_ASSERT(sizeof(struct ofp_port_status) == 80); -/* What changed about the physical port */ -enum ofp_port_reason { - OFPPR_ADD = 0, /* The port was added. */ - OFPPR_DELETE = 1, /* The port was removed. */ - OFPPR_MODIFY = 2, /* Some attribute of the port has changed. */ +/* 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 alignment. */ }; +OFP_ASSERT(sizeof(struct ofp_queue_prop_header) == 8); -/* 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. No padding. */ +/* 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_error_msg) == 12); +OFP_ASSERT(sizeof(struct ofp_queue_prop_min_rate) == 16); -/* 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 = 0, /* Hello protocol failed. */ - OFPET_BAD_REQUEST = 1, /* Request was not understood. */ - OFPET_BAD_ACTION = 2, /* Error in action description. */ - OFPET_BAD_INSTRUCTION = 3, /* Error in instruction list. */ - OFPET_BAD_MATCH = 4, /* Error in match. */ - OFPET_FLOW_MOD_FAILED = 5, /* Problem modifying flow entry. */ - OFPET_GROUP_MOD_FAILED = 6, /* Problem modifying group entry. */ - OFPET_PORT_MOD_FAILED = 7, /* Port mod request failed. */ - OFPET_TABLE_MOD_FAILED = 8, /* Table mod request failed. */ - OFPET_QUEUE_OP_FAILED = 9, /* Queue operation failed. */ - OFPET_SWITCH_CONFIG_FAILED = 10, /* Switch config request failed. */ - OFPET_ROLE_REQUEST_FAILED = 11, /* Controller Role request failed. */ - OFPET_METER_MOD_FAILED = 12, /* Error in meter. */ - OFPET_TABLE_FEATURES_FAILED = 13, /* Setting table features failed. */ - OFPET_EXPERIMENTER = 0xffff /* Experimenter error messages. */ +/* Max-Rate queue property description. */ +struct ofp_queue_prop_max_rate { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_MAX, 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_max_rate) == 16); -/* 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 = 0, /* No compatible version. */ - OFPHFC_EPERM = 1, /* Permissions error. */ +/* Experimenter queue property description. */ +struct ofp_queue_prop_experimenter { + struct ofp_queue_prop_header prop_header; /* prop: OFPQT_EXPERIMENTER, len: 16. */ + uint32_t experimenter; /* Experimenter ID which takes the same + form as in struct + ofp_experimenter_header. */ + uint8_t pad[4]; /* 64-bit alignment */ + uint8_t data[0]; /* Experimenter defined data. */ }; +OFP_ASSERT(sizeof(struct ofp_queue_prop_experimenter) == 16); -/* 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 = 0, /* ofp_header.version not supported. */ - OFPBRC_BAD_TYPE = 1, /* ofp_header.type not supported. */ - OFPBRC_BAD_MULTIPART = 2, /* ofp_multipart_request.type not supported. */ - OFPBRC_BAD_EXPERIMENTER = 3, /* Experimenter id not supported - * (in ofp_experimenter_header or - * ofp_multipart_request or ofp_multipart_reply). */ - OFPBRC_BAD_EXP_TYPE = 4, /* Experimenter type not supported. */ - OFPBRC_EPERM = 5, /* Permissions error. */ - OFPBRC_BAD_LEN = 6, /* Wrong request length for type. */ - OFPBRC_BUFFER_EMPTY = 7, /* Specified buffer has already been used. */ - OFPBRC_BUFFER_UNKNOWN = 8, /* Specified buffer does not exist. */ - OFPBRC_BAD_TABLE_ID = 9, /* Specified table-id invalid or does not - * exist. */ - OFPBRC_IS_SLAVE = 10, /* Denied because controller is slave. */ - OFPBRC_BAD_PORT = 11, /* Invalid port. */ - OFPBRC_BAD_PACKET = 12, /* Invalid packet in packet-out. */ - OFPBRC_MULTIPART_BUFFER_OVERFLOW = 13, /* ofp_multipart_request - overflowed the assigned buffer. */ - -}; - -/* 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 = 0, /* Unknown action type. */ - OFPBAC_BAD_LEN = 1, /* Length problem in actions. */ - OFPBAC_BAD_EXPERIMENTER = 2, /* Unknown experimenter id specified. */ - OFPBAC_BAD_EXP_TYPE = 3, /* Unknown action for experimenter id. */ - OFPBAC_BAD_OUT_PORT = 4, /* Problem validating output port. */ - OFPBAC_BAD_ARGUMENT = 5, /* Bad action argument. */ - OFPBAC_EPERM = 6, /* Permissions error. */ - OFPBAC_TOO_MANY = 7, /* Can’t handle this many actions. */ - OFPBAC_BAD_QUEUE = 8, /* Problem validating output queue. */ - OFPBAC_BAD_OUT_GROUP = 9, /* Invalid group id in forward action. */ - OFPBAC_MATCH_INCONSISTENT = 10, /* Action can’t apply for this match, - or Set-Field missing prerequisite. */ - OFPBAC_UNSUPPORTED_ORDER = 11, /* Action order is unsupported for the - action list in an Apply-Actions instruction */ - OFPBAC_BAD_TAG = 12, /* Actions uses an unsupported - tag/encap. */ - OFPBAC_BAD_SET_TYPE = 13, /* Unsupported type in SET_FIELD action. */ - OFPBAC_BAD_SET_LEN = 14, /* Length problem in SET_FIELD action. */ - OFPBAC_BAD_SET_ARGUMENT = 15, /* Bad argument in SET_FIELD action. */ +/* Full description for a queue. */ +struct ofp_packet_queue { + uint32_t queue_id; /* id for the specific queue. */ + uint32_t port; /* Port this queue is attached to. */ + uint16_t len; /* Length in bytes of this queue desc. */ + uint8_t pad[6]; /* 64-bit alignment. */ + struct ofp_queue_prop_header properties[0]; /* List of properties. */ }; +OFP_ASSERT(sizeof(struct ofp_packet_queue) == 16); -/* ofp_error_msg ’code’ values for OFPET_BAD_INSTRUCTION. ’data’ contains at least -* the first 64 bytes of the failed request. */ -enum ofp_bad_instruction_code { - OFPBIC_UNKNOWN_INST = 0, /* Unknown instruction. */ - OFPBIC_UNSUP_INST = 1, /* Switch or table does not support the - instruction. */ - OFPBIC_BAD_TABLE_ID = 2, /* Invalid Table-ID specified. */ - OFPBIC_UNSUP_METADATA = 3, /* Metadata value unsupported by datapath. */ - OFPBIC_UNSUP_METADATA_MASK = 4, /* Metadata mask value unsupported by - datapath. */ - OFPBIC_BAD_EXPERIMENTER = 5, /* Unknown experimenter id specified. */ - OFPBIC_BAD_EXP_TYPE = 6, /* Unknown instruction for experimenter id. */ - OFPBIC_BAD_LEN = 7, /* Length problem in instructions. */ - OFPBIC_EPERM = 8, /* Permissions error. */ +/* Query for port queue configuration. */ +struct ofp_queue_get_config_request { + struct ofp_header header; + uint32_t port; /* Port to be queried. Should refer + to a valid physical port (i.e. <= OFPP_MAX), + or OFPP_ANY to request all configured + queues.*/ + uint8_t pad[4]; }; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_request) == 16); -/* ofp_error_msg ’code’ values for OFPET_BAD_MATCH. ’data’ contains at least -* the first 64 bytes of the failed request. */ -enum ofp_bad_match_code { - OFPBMC_BAD_TYPE = 0, /* Unsupported match type specified by the - match */ - OFPBMC_BAD_LEN = 1, /* Length problem in match. */ - OFPBMC_BAD_TAG = 2, /* Match uses an unsupported tag/encap. */ - OFPBMC_BAD_DL_ADDR_MASK = 3, /* Unsupported datalink addr mask - switch - does not support arbitrary datalink - address mask. */ - OFPBMC_BAD_NW_ADDR_MASK = 4, /* Unsupported network addr mask - switch - does not support arbitrary network - address mask. */ - OFPBMC_BAD_WILDCARDS = 5, /* Unsupported combination of fields masked - or omitted in the match. */ - OFPBMC_BAD_FIELD = 6, /* Unsupported field type in the match. */ - OFPBMC_BAD_VALUE = 7, /* Unsupported value in a match field. */ - OFPBMC_BAD_MASK = 8, /* Unsupported mask specified in the match, - field is not dl-address or nw-address. */ - OFPBMC_BAD_PREREQ = 9, /* A prerequisite was not met. */ - OFPBMC_DUP_FIELD = 10, /* A field type was duplicated. */ - OFPBMC_EPERM = 11, /* Permissions error. */ -}; - -/* 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_UNKNOWN = 0, /* Unspecified error. */ - OFPFMFC_TABLE_FULL = 1, /* Flow not added because table was full. */ - OFPFMFC_BAD_TABLE_ID = 2, /* Table does not exist */ - OFPFMFC_OVERLAP = 3, /* Attempted to add overlapping flow with - CHECK_OVERLAP flag set. */ - OFPFMFC_EPERM = 4, /* Permissions error. */ - OFPFMFC_BAD_TIMEOUT = 5, /* Flow not added because of unsupported - idle/hard timeout. */ - OFPFMFC_BAD_COMMAND = 6, /* Unsupported or unknown command. */ - OFPFMFC_BAD_FLAGS = 7, /* Unsupported or unknown flags. */ -}; - -/* ofp_error_msg ’code’ values for OFPET_GROUP_MOD_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_group_mod_failed_code { - OFPGMFC_GROUP_EXISTS = 0, /* Group not added because a group ADD - attempted to replace an - already-present group. */ - OFPGMFC_INVALID_GROUP = 1, /* Group not added because Group */ - - OFPGMFC_OUT_OF_GROUPS = 3, /* The group table is full. */ - - OFPGMFC_OUT_OF_BUCKETS = 4, /* The maximum number of action buckets - for a group has been exceeded. */ - OFPGMFC_CHAINING_UNSUPPORTED = 5, /* Switch does not support groups that - forward to groups. */ - OFPGMFC_WATCH_UNSUPPORTED = 6, /* This group cannot watch the watch_port - or watch_group specified. */ - OFPGMFC_LOOP = 7, /* Group entry would cause a loop. */ - OFPGMFC_UNKNOWN_GROUP = 8, /* Group not modified because a group - MODIFY attempted to modify a - non-existent group. */ - OFPGMFC_CHAINED_GROUP = 9, /* Group not deleted because another - group is forwarding to it. */ - OFPGMFC_BAD_TYPE = 10, /* Unsupported or unknown group type. */ - OFPGMFC_BAD_COMMAND = 11, /* Unsupported or unknown command. */ - OFPGMFC_BAD_BUCKET = 12, /* Error in bucket. */ - OFPGMFC_BAD_WATCH = 13, /* Error in watch port/group. */ - OFPGMFC_EPERM = 14, /* Permissions error. */ -}; - -/* 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 = 0, /* Specified port number does not exist. */ - OFPPMFC_BAD_HW_ADDR = 1, /* Specified hardware address does not - * match the port number. */ - OFPPMFC_BAD_CONFIG = 2, /* Specified config is invalid. */ - OFPPMFC_BAD_ADVERTISE = 3, /* Specified advertise is invalid. */ - OFPPMFC_EPERM = 4, /* Permissions error. */ +/* Queue configuration for a given port. */ +struct ofp_queue_get_config_reply { + struct ofp_header header; + uint32_t port; + uint8_t pad[4]; + struct ofp_packet_queue queues[0]; /* List of configured queues. */ }; +OFP_ASSERT(sizeof(struct ofp_queue_get_config_reply) == 16); -/* ofp_error_msg ’code’ values for OFPET_TABLE_MOD_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_table_mod_failed_code { - OFPTMFC_BAD_TABLE = 0, /* Specified table does not exist. */ - OFPTMFC_BAD_CONFIG = 1, /* Specified config is invalid. */ - OFPTMFC_EPERM = 2, /* Permissions error. */ +/* OFPAT_SET_QUEUE action struct: send packets to given queue on port. */ +struct ofp_action_set_queue { + uint16_t type; /* OFPAT_SET_QUEUE. */ + uint16_t len; /* Len is 8. */ + uint32_t queue_id; /* Queue id for the packets. */ }; +OFP_ASSERT(sizeof(struct ofp_action_set_queue) == 8); -/* 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 = 0, /* Invalid port (or port does not exist). */ - OFPQOFC_BAD_QUEUE = 1, /* Queue does not exist. */ - OFPQOFC_EPERM = 2, /* Permissions error. */ +struct ofp_queue_stats_request { + uint32_t port_no; /* All ports if OFPP_ANY. */ + uint32_t queue_id; /* All queues if OFPQ_ALL. */ }; +OFP_ASSERT(sizeof(struct ofp_queue_stats_request) == 8); -/* ofp_error_msg ’code’ values for OFPET_SWITCH_CONFIG_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_switch_config_failed_code { - OFPSCFC_BAD_FLAGS = 0, /* Specified flags is invalid. */ - OFPSCFC_BAD_LEN = 1, /* Specified len is invalid. */ - OFPQCFC_EPERM = 2, /* Permissions error. */ +struct ofp_queue_stats { + uint32_t port_no; + 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. */ + uint32_t duration_sec; /* Time queue has been alive in seconds. */ + uint32_t duration_nsec; /* Time queue has been alive in nanoseconds beyond + duration_sec. */ }; +OFP_ASSERT(sizeof(struct ofp_queue_stats) == 40); -/* ofp_error_msg ’code’ values for OFPET_ROLE_REQUEST_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_role_request_failed_code { - OFPRRFC_STALE = 0, /* Stale Message: old generation_id. */ - OFPRRFC_UNSUP = 1, /* Controller role change unsupported. */ - OFPRRFC_BAD_ROLE = 2, /* Invalid role. */ -}; +/* Configures the "role" of the sending controller. The default role is: + * + * - Equal (OFPCR_ROLE_EQUAL), which allows the controller access to all + * OpenFlow features. All controllers have equal responsibility. + * + * The other possible roles are a related pair: + * + * - Master (OFPCR_ROLE_MASTER) is equivalent to Equal, except that there + * may be at most one Master controller at a time: when a controller + * configures itself as Master, any existing Master is demoted to the + * Slave role. + * + * - Slave (OFPCR_ROLE_SLAVE) allows the controller read-only access to + * OpenFlow features. In particular attempts to modify the flow table + * will be rejected with an OFPBRC_EPERM error. + * + * Slave controllers do not receive OFPT_PACKET_IN or OFPT_FLOW_REMOVED + * messages, but they do receive OFPT_PORT_STATUS messages. + */ -/* ofp_error_msg ’code’ values for OFPET_METER_MOD_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_meter_mod_failed_code { - OFPMMFC_UNKNOWN = 0, /* Unspecified error. */ - OFPMMFC_METER_EXISTS = 1, /* Meter not added because a Meter ADD - * attempted to replace an existing Meter. */ - OFPMMFC_INVALID_METER = 2, /* Meter not added because Meter specified - * is invalid. */ - OFPMMFC_UNKNOWN_METER = 3, /* Meter not modified because a Meter - MODIFY attempted to modify a non-existent - Meter. */ - OFPMMFC_BAD_COMMAND = 4, /* Unsupported or unknown command. */ - OFPMMFC_BAD_FLAGS = 5, /* Flag configuration unsupported. */ - OFPMMFC_BAD_RATE = 6, /* Rate unsupported. */ - OFPMMFC_BAD_BURST = 7, /* Burst size unsupported. */ - OFPMMFC_BAD_BAND = 8, /* Band unsupported. */ - OFPMMFC_BAD_BAND_VALUE = 9, /* Band value unsupported. */ - OFPMMFC_OUT_OF_METERS = 10, /* No more meters available. */ - OFPMMFC_OUT_OF_BANDS = 11, /* The maximum number of properties - * for a meter has been exceeded. */ +/* Controller roles. */ +enum ofp_controller_role { + OFPCR_ROLE_NOCHANGE = 0, /* Don't change current role. */ + OFPCR_ROLE_EQUAL = 1, /* Default role, full access. */ + OFPCR_ROLE_MASTER = 2, /* Full access, at most one master. */ + OFPCR_ROLE_SLAVE = 3, /* Read-only access. */ }; -/* ofp_error_msg ’code’ values for OFPET_TABLE_FEATURES_FAILED. ’data’ contains -* at least the first 64 bytes of the failed request. */ -enum ofp_table_features_failed_code { - OFPTFFC_BAD_TABLE = 0, /* Specified table does not exist. */ - OFPTFFC_BAD_METADATA = 1, /* Invalid metadata mask. */ - OFPTFFC_BAD_TYPE = 2, /* Unknown property type. */ - OFPTFFC_BAD_LEN = 3, /* Length problem in properties. */ - OFPTFFC_BAD_ARGUMENT = 4, /* Unsupported property value. */ - OFPTFFC_EPERM = 5, /* Permissions error. */ +/* Role request and reply message. */ +struct ofp_role_request { + struct ofp_header header; /* Type OFPT_ROLE_REQUEST/OFPT_ROLE_REPLY. */ + uint32_t role; /* One of OFPCR_ROLE_*. */ + uint8_t pad[4]; /* Align to 64 bits. */ + uint64_t generation_id; /* Master Election Generation Id */ }; +OFP_ASSERT(sizeof(struct ofp_role_request) == 24); -/* OFPET_EXPERIMENTER: Error message (datapath -> controller). */ -struct ofp_error_experimenter_msg { - struct ofp_header header; - uint16_t type; /* OFPET_EXPERIMENTER. */ - uint16_t exp_type; /* Experimenter defined. */ - uint32_t experimenter; /* Experimenter ID which takes the same form - as in struct ofp_experimenter_header. */ - uint8_t data[0]; /* Variable-length data. Interpreted based - on the type and code. No padding. */ +/* Asynchronous message configuration. */ +struct ofp_async_config { + struct ofp_header header; /* OFPT_GET_ASYNC_REPLY or OFPT_SET_ASYNC. */ + uint32_t packet_in_mask[2]; /* Bitmasks of OFPR_* values. */ + uint32_t port_status_mask[2]; /* Bitmasks of OFPPR_* values. */ + uint32_t flow_removed_mask[2];/* Bitmasks of OFPRR_* values. */ }; -OFP_ASSERT(sizeof(struct ofp_error_experimenter_msg) == 16); +OFP_ASSERT(sizeof(struct ofp_async_config) == 32); -/* Experimenter extension. */ -struct ofp_experimenter_header { - struct ofp_header header; /* Type OFPT_EXPERIMENTER. */ - uint32_t experimenter; /* Experimenter ID: - * - MSB 0: low-order bytes are IEEE OUI. - * - MSB != 0: defined by ONF. */ - uint32_t exp_type; /* Experimenter defined. */ - /* Experimenter-defined arbitrary additional data. */ -}; -OFP_ASSERT(sizeof(struct ofp_experimenter_header) == 16); #endif /* openflow/openflow.h */ diff --git a/oflib/ofl-messages-pack.c b/oflib/ofl-messages-pack.c index 6c57e9bc..b8c418d3 100644 --- a/oflib/ofl-messages-pack.c +++ b/oflib/ofl-messages-pack.c @@ -732,13 +732,13 @@ ofl_msg_pack_multipart_reply_group_desc(struct ofl_msg_multipart_reply_group_des static int ofl_msg_pack_multipart_reply_group_features(struct ofl_msg_multipart_reply_group_features *msg, uint8_t **buf, size_t *buf_len) { struct ofp_multipart_reply *resp; - struct ofp_group_features_stats *stats; + struct ofp_group_features *stats; int i; - *buf_len = sizeof(struct ofp_multipart_reply) + sizeof(struct ofp_group_features_stats); + *buf_len = sizeof(struct ofp_multipart_reply) + sizeof(struct ofp_group_features); *buf = (uint8_t *)malloc(*buf_len); resp = (struct ofp_multipart_reply *)(*buf); - stats = (struct ofp_group_features_stats *)resp->body; + stats = (struct ofp_group_features *)resp->body; stats->types = htonl(msg->types); stats->capabilities = htonl(msg->capabilities); for(i = 0; i < 4; i++){ diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index a13ec519..c66e62dc 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -1222,16 +1222,16 @@ ofl_msg_unpack_multipart_reply_group_desc(struct ofp_multipart_reply *os, size_t static ofl_err ofl_msg_unpack_multipart_reply_group_features(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { - struct ofp_group_features_stats *sm; + struct ofp_group_features *sm; struct ofl_msg_multipart_reply_group_features *dm; int i; - if (*len < sizeof(struct ofp_group_features_stats)) { + if (*len < sizeof(struct ofp_group_features)) { OFL_LOG_WARN(LOG_MODULE, "Received OFPMP_GROUP_FEATURES stats reply has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } - *len -= sizeof(struct ofp_group_features_stats); + *len -= sizeof(struct ofp_group_features); - sm = (struct ofp_group_features_stats *)os->body; + sm = (struct ofp_group_features *)os->body; dm = (struct ofl_msg_multipart_reply_group_features *) malloc(sizeof(struct ofl_msg_multipart_reply_group_features)); dm->types = ntohl(sm->types); diff --git a/oflib/ofl-structs-pack.c b/oflib/ofl-structs-pack.c index 376741fa..7291af03 100644 --- a/oflib/ofl-structs-pack.c +++ b/oflib/ofl-structs-pack.c @@ -94,8 +94,6 @@ size_t ofl_structs_instructions_pack(struct ofl_instruction_header *src, struct ofp_instruction *dst, struct ofl_exp *exp) { dst->type = htons(src->type); - memset(dst->pad, 0x00, 4); - switch (src->type) { case OFPIT_GOTO_TABLE: { struct ofl_instruction_goto_table *si = (struct ofl_instruction_goto_table *)src; diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index 2cba7059..6fd800ad 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -391,20 +391,20 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) case OFPXMT_OFB_MPLS_LABEL: fprintf(stream, "mpls_label=\"%d\"",((uint32_t) *f->value) & 0x000fffff); break; - case OFPXMT_OFB_MPLS_TC: + case OXM_OF_MPLS_TC: fprintf(stream, "mpls_tc=\"%d\"", *f->value & 0x3); break; - case OFPXMT_OFB_MPLS_BOS: + case OXM_OF_MPLS_BOS: fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0x1); break; - case OFPXMT_OFB_METADATA: - fprintf(stream, "metadata=\"0x%"PRIx64"\"", *((uint64_t*) f->value)); + case OXM_OF_METADATA: + fprintf(stream, "metadata=\"0x%llx\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", metadata_mask=\"0x%"PRIx64"\"", *((uint64_t*)(f->value+8))); } break; - case OFPXMT_OFB_PBB_ISID : - fprintf(stream, "pbb_isid=\"%x%x%x\"", f->value[0],f->value[1], f->value[2]); + case OXM_OF_PBB_ISID : + fprintf(stream, "pbb_isid=\"%d\"", *((uint32_t*) f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", pbb_isid_mask=\"%x%x%x\"", (f->value+4)[0], (f->value+4)[1], (f->value+4)[2]); } diff --git a/oflib/oxm-match.c b/oflib/oxm-match.c index 9282474a..36725be7 100644 --- a/oflib/oxm-match.c +++ b/oflib/oxm-match.c @@ -568,7 +568,7 @@ oxm_pull_match(struct ofpbuf *buf, struct ofl_match * match_dst, int match_len) if (!p) { VLOG_DBG_RL(LOG_MODULE,&rl, "oxm_match length %u, rounded up to a " "multiple of 8, is longer than space in message (max " - "length %zd)", match_len, buf->size); + "length %zu)", match_len, buf->size); return ofp_mkerr(OFPET_BAD_MATCH, OFPBRC_BAD_LEN); } diff --git a/oflib/oxm-match.h b/oflib/oxm-match.h index c5dbbf8c..605cf4fa 100644 --- a/oflib/oxm-match.h +++ b/oflib/oxm-match.h @@ -43,8 +43,8 @@ * limitations under the License. */ -#ifndef OX_MATCH_H -#define OX_MATCH_H 1 +#ifndef OXM_MATCH_H +#define OXM_MATCH_H 1 #include #include @@ -52,20 +52,9 @@ #include "ofpbuf.h" #include "hmap.h" #include "packets.h" +#include "openflow/openflow.h" #include "../oflib/ofl-structs.h" -#define OXM_HEADER__(VENDOR, FIELD, HASMASK, LENGTH) \ - (((VENDOR) << 16) | ((FIELD) << 9) | ((HASMASK) << 8) | (LENGTH)) -#define OXM_HEADER(VENDOR, FIELD, LENGTH) \ - OXM_HEADER__(VENDOR, FIELD, 0, LENGTH) -#define OXM_HEADER_W(VENDOR, FIELD, LENGTH) \ - OXM_HEADER__(VENDOR, FIELD, 1, (LENGTH) * 2) - -#define OXM_HEADER_VL(VENDOR,FIELD) \ - OXM_HEADER__(VENDOR,FIELD,0,0) - -#define OXM_HEADER_VL_W(VENDOR,FIELD) \ - OXM_HEADER__(VENDOR,FIELD,1,0) #define OXM_VENDOR(HEADER) ((HEADER) >> 16) #define OXM_FIELD(HEADER) (((HEADER) >> 9) & 0x7f) @@ -75,211 +64,6 @@ #define VENDOR_FROM_TYPE(TYPE) ((TYPE) >> 7) #define FIELD_FROM_TYPE(TYPE) ((TYPE) & 0x7f) -#define OXM_MAKE_WILD_HEADER(HEADER) \ - OXM_HEADER_W(OXM_VENDOR(HEADER), OXM_FIELD(HEADER), OXM_LENGTH(HEADER)) - -/* ## ------------------------------- ## */ -/* ## OpenFlow 1.2-compatible fields. ## */ -/* ## ------------------------------- ## */ - -/* Physical or virtual port on which the packet was received. - * - * Prereqs: None. - * - * Format: 16-bit integer. */ -#define OXM_OF_IN_PORT OXM_HEADER (0x8000, 0, 4) - - -/* Physical port on which the packet was received. - * - * Prereqs: None. - * - * Format: 32-bit integer. */ -#define OXM_OF_IN_PHY_PORT OXM_HEADER (0x8000, 1, 4) - -/* Metadata passed btw tables. */ -#define OXM_OF_METADATA OXM_HEADER (0x8000, 2, 8) -#define OXM_OF_METADATA_W OXM_HEADER_W (0x8000, 2, 8) - -/* Ethernet destination address.*/ -#define OXM_OF_ETH_DST OXM_HEADER (0x8000,3,6) -#define OXM_OF_ETH_DST_W OXM_HEADER_W(0x8000,3,6) - -/* Ethernet source address.*/ -#define OXM_OF_ETH_SRC OXM_HEADER (0x8000, 4,6) -#define OXM_OF_ETH_SRC_W OXM_HEADER_W(0x8000,4,6) - -/* Ethernet frame type. */ -#define OXM_OF_ETH_TYPE OXM_HEADER (0x8000, 5, 2) - -/* VLAN id. */ -#define OXM_OF_VLAN_VID OXM_HEADER (0x8000, 6, 2) -#define OXM_OF_VLAN_VID_W OXM_HEADER_W (0x8000, 6, 2) - - /* VLAN priority. */ -#define OXM_OF_VLAN_PCP OXM_HEADER (0x8000, 7, 1) - - -/* IP ToS (DSCP field, 6 bits). */ -#define OXM_OF_IP_DSCP OXM_HEADER (0x8000, 8, 1) - -/* IP ECN */ -#define OXM_OF_IP_ECN OXM_HEADER (0x8000, 9, 1) - -/* IP protocol. */ -#define OXM_OF_IP_PROTO OXM_HEADER (0x8000, 10, 1) - - /* IP source address. */ -#define OXM_OF_IPV4_SRC OXM_HEADER (0x8000,11, 4) -#define OXM_OF_IPV4_SRC_W OXM_HEADER_W (0x8000,11, 4) - -/* IP destination address. */ -#define OXM_OF_IPV4_DST OXM_HEADER (0x8000,12 , 4) -#define OXM_OF_IPV4_DST_W OXM_HEADER_W (0x8000,12 , 4) - -/* TCP source port. */ -#define OXM_OF_TCP_SRC OXM_HEADER (0x8000, 13, 2) - - /* TCP destination port. */ -#define OXM_OF_TCP_DST OXM_HEADER (0x8000, 14, 2) - -/* UDP source port. */ -#define OXM_OF_UDP_SRC OXM_HEADER (0x8000, 15, 2) - - /* UDP destination port. */ -#define OXM_OF_UDP_DST OXM_HEADER (0x8000, 16, 2) - -/* SCTP source port. */ -#define OXM_OF_SCTP_SRC OXM_HEADER (0x8000, 17, 2) - - /* SCTP destination port. */ -#define OXM_OF_SCTP_DST OXM_HEADER (0x8000, 18, 2) - -/* ICMPv4 type. */ -#define OXM_OF_ICMPV4_TYPE OXM_HEADER (0x8000, 19, 1) - -/* ICMPv4 code. */ -#define OXM_OF_ICMPV4_CODE OXM_HEADER (0x8000, 20, 1) - - /* ARP operation code. */ -#define OXM_OF_ARP_OP OXM_HEADER (0x8000,21, 2) - - /* IPv4 source address of ARP. */ -#define OXM_OF_ARP_SPA OXM_HEADER (0x8000,22, 4) -#define OXM_OF_ARP_SPA_W OXM_HEADER_W (0x8000,22, 4) - -/* IPv4 destination address of ARP. */ -#define OXM_OF_ARP_TPA OXM_HEADER (0x8000,23 , 4) -#define OXM_OF_ARP_TPA_W OXM_HEADER_W (0x8000,23 , 4) - -/* ARP Ethernet destination address.*/ -#define OXM_OF_ARP_SHA OXM_HEADER (0x8000,24,6) -#define OXM_OF_ARP_SHA_W OXM_HEADER_W(0x8000,24,6) - -/* ARP Ethernet source address.*/ -#define OXM_OF_ARP_THA OXM_HEADER (0x8000, 25,6) -#define OXM_OF_ARP_THA_W OXM_HEADER_W(0x8000,25,6) - -/* IPv6 source address */ -#define OXM_OF_IPV6_SRC OXM_HEADER (0x8000, 26, 16) -#define OXM_OF_IPV6_SRC_W OXM_HEADER_W(0x8000, 26, 16) - -/* IPv6 destination address*/ -#define OXM_OF_IPV6_DST OXM_HEADER (0x8000, 27, 16) -#define OXM_OF_IPV6_DST_W OXM_HEADER_W(0x8000, 27, 16) - -/* IPv6 flow label*/ -#define OXM_OF_IPV6_FLABEL OXM_HEADER (0x8000, 28, 4) -#define OXM_OF_IPV6_FLABEL_W OXM_HEADER_W (0x8000, 28, 4) - -/* ICMPv6 message type field */ -#define OXM_OF_ICMPV6_TYPE OXM_HEADER (0x8000, 29, 1) - -/* ICMPv6 type code */ -#define OXM_OF_ICMPV6_CODE OXM_HEADER (0x8000, 30, 1) - -/* IPv6 nd target*/ -#define OXM_OF_IPV6_ND_TARGET OXM_HEADER (0x8000, 31, 16) - -/* IPv6 nd target*/ -#define OXM_OF_IPV6_ND_SLL OXM_HEADER (0x8000, 32, 6) - -/* IPv6 dnd target*/ -#define OXM_OF_IPV6_ND_TLL OXM_HEADER (0x8000, 33, 6) - -/* MPLS label. */ -#define OXM_OF_MPLS_LABEL OXM_HEADER (0x8000, 34, 4) - -/* MPLS TC. */ -#define OXM_OF_MPLS_TC OXM_HEADER (0x8000, 35, 1) - -#define OXM_OF_MPLS_BOS OXM_HEADER (0x8000, 36, 1) - -#define OXM_OF_PBB_ISID OXM_HEADER (0x8000, 37, 3) -#define OXM_OF_PBB_ISID_W OXM_HEADER_W (0x8000, 37, 3) - -#define OXM_OF_TUNNEL_ID OXM_HEADER (0x8000, 38, 8) -#define OXM_OF_TUNNEL_ID_W OXM_HEADER_W (0x8000, 38, 8) - -#define OXM_OF_IPV6_EXTHDR OXM_HEADER (0x8000, 39, 2) -#define OXM_OF_IPV6_EXTHDR_W OXM_HEADER_W (0x8000, 39, 2) - -/* ## ------------------------------- ## */ -/* ## IPv6 compatible fields. ## */ -/* ## ------------------------------- ## */ - - -/* Traffic Class */ -#define OXM_OF_IPV6_TC OXM_HEADER (0x0002, 5, 1) -#define OXM_OF_IPV6_TC_W OXM_HEADER_W (0x0002, 5, 1) - -/* IPv6 Hop-by-Hop EH ID*/ -#define OXM_OF_IPV6_HBH_ID OXM_HEADER (0x0002, 8, 1) -#define OXM_OF_IPV6_HBH_ID_W OXM_HEADER_W (0x0002, 8, 1) - -#define OXM_OF_IPV6_HBH_OPT_CODE OXM_HEADER (0x0002, 9, 1) - -#define OXM_OF_IPV6_HBH_OPT_VALUE OXM_HEADER_VL (0x0002, 10) - -/* IPv6 Destination Option EH ID*/ -#define OXM_OF_IPV6_DOH_ID OXM_HEADER (0x0002, 16, 1) -#define OXM_OF_IPV6_DOH_ID_W OXM_HEADER_W (0x0002, 16, 1) - -#define OXM_OF_IPV6_DOH_OPT_CODE OXM_HEADER (0x0002, 17, 1) - -#define OXM_OF_IPV6_DOH_OPT_VALUE OXM_HEADER_VL (0x0002, 18) - - -/* IPv6 Routing EH ID*/ -#define OXM_OF_IPV6_RH_ID OXM_HEADER (0x0002, 24, 1) -#define OXM_OF_IPV6_RH_ID_W OXM_HEADER_W (0x0002, 24, 1) - -#define OXM_OF_IPV6_RH_ADDRESS OXM_HEADER (0x0002, 25, 16) - -/* IPv6 Fragmentation EH ID*/ -#define OXM_OF_IPV6_FH_ID OXM_HEADER (0x0002, 32, 1) -#define OXM_OF_IPV6_FH_ID_W OXM_HEADER_W (0x0002, 32, 1) - -/* IPv6 Authentication EH ID*/ -#define OXM_OF_IPV6_AH_ID OXM_HEADER (0x0002, 40, 1) -#define OXM_OF_IPV6_AH_ID_W OXM_HEADER_W (0x0002, 40, 1) - -/* IPv6 Encapsulating Security Payload */ -#define OXM_OF_IPV6_ESP_ID OXM_HEADER (0x0002, 48, 1) - -/* IPv6 Mobility EH */ -#define OXM_OF_IPV6_MH_ID OXM_HEADER (0x0002, 56, 1) - -/* ## ------------------------------- ## */ -/* ## TTL fields. ## */ -/* ## ------------------------------- ## */ - -/* MPLS TTL */ -#define OXM_OF_MPLS_TTL OXM_HEADER (0x0002, 80, 4) - -/* IPv4 TTL */ -#define OXM_OF_IPV4_TTL OXM_HEADER (0x0002, 81, 1) - enum oxm_field_index { #define DEFINE_FIELD(HEADER,DL_TYPES, NW_PROTO, MASKABLE) \ OFI_OXM_##HEADER, @@ -341,4 +125,4 @@ oxm_field_bits(uint32_t header); -#endif /* nx-match.h */ +#endif /* oxm-match.h */ diff --git a/udatapath/flow_table.c b/udatapath/flow_table.c index 760a5ed9..a905dbc9 100644 --- a/udatapath/flow_table.c +++ b/udatapath/flow_table.c @@ -397,7 +397,7 @@ flow_table_create(struct datapath *dp, uint8_t table_id) { table->features->name = ds_cstr(&string); table->features->metadata_match = 0xffffffffffffffff; table->features->metadata_write = 0xffffffffffffffff; - table->features->config = OFPTC_TABLE_MISS_CONTROLLER; + table->features->config = OFPTC_DEPRECATED_MASK; table->features->max_entries = FLOW_TABLE_MAX_ENTRIES; table->features->properties_num = flow_table_features(table->features); diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index e5a05fed..bf925632 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -46,7 +46,6 @@ #include "meter_table.h" #include "oflib/ofl.h" #include "oflib/ofl-structs.h" -#include "nbee_link/nbee_link.h" #include "util.h" #include "hash.h" #include "oflib/oxm-match.h" @@ -72,8 +71,6 @@ pipeline_create(struct datapath *dp) { } pl->dp = dp; - nblink_initialize(); - return pl; } @@ -131,13 +128,7 @@ pipeline_process_packet(struct pipeline *pl, struct packet *pkt) { } if (!packet_handle_std_is_ttl_valid(pkt->handle_std)) { - if ((pl->dp->config.flags & OFPC_INVALID_TTL_TO_CONTROLLER) != 0) { - VLOG_DBG_RL(LOG_MODULE, &rl, "Packet has invalid TTL, sending to controller."); - - send_packet_to_controller(pl, pkt, 0/*table_id*/, OFPR_INVALID_TTL); - } else { - VLOG_DBG_RL(LOG_MODULE, &rl, "Packet has invalid TTL, dropping."); - } + send_packet_to_controller(pl, pkt, 0/*table_id*/, OFPR_INVALID_TTL); packet_destroy(pkt); return; } From d2415c61c901b37d2d4ef4c29589bd18663d1c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 10:42:15 +0000 Subject: [PATCH 130/191] Fix backtrace.c warnings. Fixed a warning about assignment suppresion and another only raised on x86_64 platforms. --- lib/backtrace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/backtrace.c b/lib/backtrace.c index fc301987..8a56561f 100644 --- a/lib/backtrace.c +++ b/lib/backtrace.c @@ -59,7 +59,7 @@ get_max_stack(void) for (line_number = 1; fgets(line, sizeof line, f); line_number++) { if (strstr(line, "[stack]")) { uintptr_t end; - if (sscanf(line, "%*"SCNxPTR"-%"SCNxPTR, &end) != 1) { + if (sscanf(line, "%*x-%"SCNxPTR, &end) != 1) { VLOG_WARN(LOG_MODULE, "%s:%d: parse error", file_name, line_number); continue; } @@ -90,6 +90,10 @@ stack_low(void) uintptr_t low; asm("movl %%esp,%0" : "=g" (low)); return low; +#elif __x86_64__ + uintptr_t low; + asm("movq %%rsp,%0" : "=g" (low)); + return low; #else /* This causes a warning in GCC that cannot be disabled, so use it only on * non-x86. */ From 9d34e7534760a46a3f39bce2da928517fd1b5254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 10:42:15 +0000 Subject: [PATCH 131/191] Fix backtrace.c warnings. Fixed a warning about assignment suppresion and another only raised on x86_64 platforms. --- include/openflow/openflow.h | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 2fb42c70..3dc14125 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -71,16 +71,10 @@ #define PIPELINE_TABLES 64 #define OFP_MAX_TABLE_NAME_LEN 32 #define OFP_MAX_PORT_NAME_LEN 16 -<<<<<<< HEAD -#define OFP_TCP_PORT 6653 -#define OFP_SSL_PORT 6653 -======= - /* Official IANA registered port for OpenFlow. */ #define OFP_TCP_PORT 6653 #define OFP_SSL_PORT 6653 ->>>>>>> e309316... Update openflow.h to OpenFlow 1.3.5 #define OFP_ETH_ALEN 6 /* Bytes in an Ethernet address. */ /* Port numbering. Ports are numbered starting from 1. */ @@ -1833,24 +1827,6 @@ OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 40); /* Body of reply to OFPMP_FLOW request. */ struct ofp_flow_stats { -<<<<<<< HEAD - uint16_t length; /* Length of this entry. */ - uint8_t table_id; /* ID of table flow came from. */ - uint8_t pad; - 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. */ - uint16_t idle_timeout; /* Number of seconds idle before expiration. */ - uint16_t hard_timeout; /* Number of seconds before expiration. */ - uint16_t flags; /* One of OFPFF_*/ - uint8_t pad2[4]; /* 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_match match; /* Description of fields. Variable size. */ - //struct ofp_instruction instructions[0]; /* Instruction set. */ -======= uint16_t length; /* Length of this entry. */ uint8_t table_id; /* ID of table flow came from. */ uint8_t pad; @@ -1868,7 +1844,6 @@ struct ofp_flow_stats { struct ofp_match match; /* Description of fields. Variable size. */ /* The variable size and padded match is always followed by instructions. */ //struct ofp_instruction instructions[0]; /* Instruction set - 0 or more. */ ->>>>>>> e309316... Update openflow.h to OpenFlow 1.3.5 }; OFP_ASSERT(sizeof(struct ofp_flow_stats) == 56); From 04439b242244f15b64e68dc6ce93f893e1b46734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 11:08:44 +0000 Subject: [PATCH 132/191] Remove leak-checker. Considered dead code as Valgring has been used since the beginning of the development. What is more it contained functions deprecated on glibc for not being thread-safe. --- debian/openflow-common.install | 1 - lib/automake.mk | 4 +- lib/daemon.c | 8 +- lib/leak-checker.c | 252 ----------------------------- lib/leak-checker.h | 58 ------- lib/leak-checker.man | 7 - secchan/ofprotocol.8.in | 1 - utilities/automake.mk | 3 - utilities/ofp-parse-leaks.in | 285 --------------------------------- 9 files changed, 8 insertions(+), 611 deletions(-) delete mode 100644 lib/leak-checker.c delete mode 100644 lib/leak-checker.h delete mode 100644 lib/leak-checker.man delete mode 100755 utilities/ofp-parse-leaks.in diff --git a/debian/openflow-common.install b/debian/openflow-common.install index eed7413e..624bc344 100644 --- a/debian/openflow-common.install +++ b/debian/openflow-common.install @@ -1,3 +1,2 @@ -_debian/utilities/ofp-parse-leaks usr/bin _debian/utilities/ofp-pki usr/sbin _debian/utilities/vlogconf usr/sbin diff --git a/lib/automake.mk b/lib/automake.mk index fe7ec798..86e65195 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -31,10 +31,10 @@ lib_libopenflow_a_SOURCES = \ lib/hmap.h \ lib/ipv6_util.c \ lib/ipv6_util.h \ - lib/leak-checker.c \ - lib/leak-checker.h \ lib/list.c \ lib/list.h \ + lib/match.c \ + lib/match.c \ lib/mac-learning.c \ lib/mac-learning.h \ lib/netdev.c \ diff --git a/lib/daemon.c b/lib/daemon.c index 7a300c0d..cae95502 100644 --- a/lib/daemon.c +++ b/lib/daemon.c @@ -223,10 +223,14 @@ daemonize(void) /* Child process. */ close(fds[0]); make_pidfile(); - write(fds[1], &c, 1); + if (write(fds[1], &c, 1) != 1){ + ofp_fatal(errno, "daemon child failed to write signal startup"); + } close(fds[1]); setsid(); - chdir("/"); + if (chdir("/") != 0){ + ofp_fatal(errno, "daemon child failed to change the current directory"); + } break; case -1: diff --git a/lib/leak-checker.c b/lib/leak-checker.c deleted file mode 100644 index b1445885..00000000 --- a/lib/leak-checker.c +++ /dev/null @@ -1,252 +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 "leak-checker.h" -#include -#include "backtrace.h" - -#define LOG_MODULE VLM_leak_checker -#include "vlog.h" - -#ifndef HAVE_MALLOC_HOOKS -void -leak_checker_start(const char *file_name UNUSED) -{ - VLOG_WARN(LOG_MODULE, "not enabling leak checker because the libc in use does not " - "have the required hooks"); -} - -void -leak_checker_set_limit(off_t max_size UNUSED) -{ -} - -void -leak_checker_claim(const void *p UNUSED) -{ -} - -void -leak_checker_usage(void) -{ - printf(" --check-leaks=FILE (accepted but ignored in this build)\n"); -} -#else /* HAVE_MALLOC_HOOKS */ -#include -#include -#include -#include - -typedef void *malloc_hook_type(size_t, const void *); -typedef void *realloc_hook_type(void *, size_t, const void *); -typedef void free_hook_type(void *, const void *); - -struct hooks { - malloc_hook_type *malloc_hook_func; - realloc_hook_type *realloc_hook_func; - free_hook_type *free_hook_func; -}; - -static malloc_hook_type hook_malloc; -static realloc_hook_type hook_realloc; -static free_hook_type hook_free; - -static struct hooks libc_hooks; -static const struct hooks our_hooks = { hook_malloc, hook_realloc, hook_free }; - -static FILE *file; -static off_t limit = 10 * 1000 * 1000; - -static void -get_hooks(struct hooks *hooks) -{ - hooks->malloc_hook_func = __malloc_hook; - hooks->realloc_hook_func = __realloc_hook; - hooks->free_hook_func = __free_hook; -} - -static void -set_hooks(const struct hooks *hooks) -{ - __malloc_hook = hooks->malloc_hook_func; - __realloc_hook = hooks->realloc_hook_func; - __free_hook = hooks->free_hook_func; -} - -void -leak_checker_start(const char *file_name) -{ - if (!file) { - file = fopen(file_name, "w"); - if (!file) { - VLOG_WARN(LOG_MODULE, "failed to create \"%s\": %s", - file_name, strerror(errno)); - return; - } - setvbuf(file, NULL, _IONBF, 0); - VLOG_WARN(LOG_MODULE, "enabled memory leak logging to \"%s\"", file_name); - get_hooks(&libc_hooks); - set_hooks(&our_hooks); - } -} - -void -leak_checker_stop(void) -{ - if (file) { - fclose(file); - file = NULL; - set_hooks(&libc_hooks); - VLOG_WARN(LOG_MODULE, "disabled memory leak logging"); - } -} - -void -leak_checker_set_limit(off_t limit_) -{ - limit = limit_; -} - -void -leak_checker_usage(void) -{ - printf(" --check-leaks=FILE log malloc and free calls to FILE\n"); -} - -static void PRINTF_FORMAT(1, 2) -log_callers(const char *format, ...) -{ - struct backtrace backtrace; - va_list args; - int i; - - va_start(args, format); - vfprintf(file, format, args); - va_end(args); - - putc(':', file); - backtrace_capture(&backtrace); - for (i = 0; i < backtrace.n_frames; i++) { - fprintf(file, " 0x%"PRIxPTR"", backtrace.frames[i]); - } - putc('\n', file); -} - -static void -reset_hooks(void) -{ - static int count; - - if (count++ >= 100 && limit && file) { - struct stat s; - count = 0; - if (fstat(fileno(file), &s) < 0) { - VLOG_WARN(LOG_MODULE, "cannot fstat leak checker log file: %s", - strerror(errno)); - return; - } - if (s.st_size > limit) { - VLOG_WARN(LOG_MODULE, "leak checker log file size exceeded limit"); - leak_checker_stop(); - return; - } - } - if (file) { - set_hooks(&our_hooks); - } -} - -static void * -hook_malloc(size_t size, const void *caller UNUSED) -{ - void *p; - - set_hooks(&libc_hooks); - p = malloc(size); - get_hooks(&libc_hooks); - - log_callers("malloc(%zu) -> %p", size, p); - - reset_hooks(); - return p; -} - -void -leak_checker_claim(const void *p) -{ - if (!file) { - return; - } - - if (p) { - set_hooks(&libc_hooks); - log_callers("claim(%p)", p); - reset_hooks(); - } -} - -static void -hook_free(void *p, const void *caller UNUSED) -{ - if (!p) { - return; - } - - set_hooks(&libc_hooks); - free(p); - get_hooks(&libc_hooks); - - log_callers("free(%p)", p); - - reset_hooks(); -} - -static void * -hook_realloc(void *p, size_t size, const void *caller UNUSED) -{ - void *q; - - set_hooks(&libc_hooks); - q = realloc(p, size); - get_hooks(&libc_hooks); - - if (p != q) { - log_callers("realloc(%p, %zu) -> %p", p, size, q); - } - - reset_hooks(); - - return q; -} -#endif /* HAVE_MALLOC_HOOKS */ diff --git a/lib/leak-checker.h b/lib/leak-checker.h deleted file mode 100644 index c0317a76..00000000 --- a/lib/leak-checker.h +++ /dev/null @@ -1,58 +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 LEAK_CHECKER_H -#define LEAK_CHECKER_H 1 - -#include - -#define LEAK_CHECKER_OPTION_ENUMS \ - OPT_CHECK_LEAKS, \ - OPT_LEAK_LIMIT -#define LEAK_CHECKER_LONG_OPTIONS \ - {"check-leaks", required_argument, 0, OPT_CHECK_LEAKS}, \ - {"leak-limit", required_argument, 0, OPT_LEAK_LIMIT} -#define LEAK_CHECKER_OPTION_HANDLERS \ - case OPT_CHECK_LEAKS: \ - leak_checker_start(optarg); \ - break; \ - case OPT_LEAK_LIMIT: \ - leak_checker_set_limit(atol(optarg)); \ - break; -void leak_checker_start(const char *file_name); -void leak_checker_set_limit(off_t limit); -void leak_checker_stop(void); -void leak_checker_claim(const void *); -void leak_checker_usage(void); - -#endif /* leak-checker.h */ diff --git a/lib/leak-checker.man b/lib/leak-checker.man deleted file mode 100644 index 7b376e1a..00000000 --- a/lib/leak-checker.man +++ /dev/null @@ -1,7 +0,0 @@ -.TP -\fB--check-leaks=\fIfile\fR -. -Logs information about memory allocation and deallocation to -\fIfile\fR, to allow for debugging memory leaks in \fB\*(PN\fR. This -option slows down \fB\*(PN\fR considerably, so it should only be used -when a memory leak is suspected. diff --git a/secchan/ofprotocol.8.in b/secchan/ofprotocol.8.in index f1d85778..13739911 100644 --- a/secchan/ofprotocol.8.in +++ b/secchan/ofprotocol.8.in @@ -450,7 +450,6 @@ require the controller to send the CA certificate, but .so lib/vlog.man .SS "Other Options" .so lib/common.man -.so lib/leak-checker.man .SH "SEE ALSO" diff --git a/utilities/automake.mk b/utilities/automake.mk index f85561c5..c484f712 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -4,7 +4,6 @@ bin_PROGRAMS += \ utilities/ofp-discover \ utilities/ofp-kill bin_SCRIPTS += utilities/ofp-pki -noinst_SCRIPTS += utilities/ofp-pki-cgi utilities/ofp-parse-leaks noinst_PROGRAMS += \ utilities/ofp-read @@ -12,7 +11,6 @@ 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 \ @@ -21,7 +19,6 @@ 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 \ diff --git a/utilities/ofp-parse-leaks.in b/utilities/ofp-parse-leaks.in deleted file mode 100755 index 059c8509..00000000 --- a/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: From 3cd4501288625817bcb0cc9b5524227d3ad7b78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 11:37:08 +0000 Subject: [PATCH 133/191] Remove warnings from netdev.c The most important change is in the position of the function pad_to_minimum_length. It was not being included in the compilation when HAVE_PACKET_AUXDATA is defined. --- lib/netdev.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/netdev.c b/lib/netdev.c index 4055889e..58b9bfdc 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -121,6 +121,7 @@ #include "socket-util.h" #include "svec.h" + /* linux/if.h defines IFF_LOWER_UP, net/if.h doesn't. * net/if.h defines if_nameindex(), linux/if.h doesn't. * We can't include both headers, so define IFF_LOWER_UP ourselves. */ @@ -450,10 +451,13 @@ static int do_remove_qdisc(const char *netdev_name) { char command[1024]; - + int error; snprintf(command, sizeof(command), COMMAND_DEL_DEV_QDISC, netdev_name); - system(command); - + error = system(command); + if (error) { + VLOG_WARN(LOG_MODULE, "Problem configuring qdisc for device %s",netdev_name); + return error; + } /* There is no need for a device to already be configured. Therefore no * need to indicate any error */ return 0; @@ -736,7 +740,6 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, int error; struct netdev *netdev; uint32_t val; - init_netdev(); *netdev_ = NULL; @@ -761,14 +764,15 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, if (netdev_fd < 0) { return errno; } - #ifdef HAVE_PACKET_AUXDATA + #ifdef HAVE_PACKET_AUXDATA val = 1; - if (setsockopt(netdev_fd, SOL_PACKET, PACKET_AUXDATA, &val, + if (setsockopt(netdev_fd, SOL_PACKET, PACKET_AUXDATA, &val, sizeof val) == -1 && errno != ENOPROTOOPT){ - VLOG_ERR(LOG_MODULE, "setsockopt(SO_RCVBUF,%"PRIu32"): %s", val, strerror(errno)); - } - #endif - + VLOG_ERR(LOG_MODULE, "setsockopt(SO_RCVBUF,%"PRIu32"): %s", val, + strerror(errno)); + } + #endif + /* Set non-blocking mode. */ error = set_nonblocking(netdev_fd); if (error) { @@ -921,7 +925,7 @@ netdev_close(struct netdev *netdev) /* Pads 'buffer' out with zero-bytes to the minimum valid length of an * Ethernet packet, if necessary. */ static void -pad_to_minimum_length(struct ofpbuf *buffer) +pad_to_minimum_length(struct ofpbuf *buffer) { if (buffer->size < ETH_TOTAL_MIN) { ofpbuf_put_zeros(buffer, ETH_TOTAL_MIN - buffer->size); @@ -1085,7 +1089,7 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer, size_t max_mtu) if (sll.sll_pkttype == PACKET_OUTGOING) { return EAGAIN; } - buffer->size += n_bytes; + buffer->size += n_bytes; #endif /* When the kernel internally sends out an Ethernet frame on an * interface, it gives us a copy *before* padding the frame to the From 9b3526fa99b4964063929cc74b58bf8a9f5818e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 11:54:35 +0000 Subject: [PATCH 134/191] Fix warnings related to write and read check. Also finishes to remove traces of the leak checker usage. --- lib/ofp.c | 9 +++++---- lib/process.c | 10 ++++++++-- lib/queue.c | 2 -- lib/signals.c | 10 ++++++++-- lib/vconn-ssl.c | 2 -- lib/vconn-stream.c | 2 -- lib/vlog-modules.def | 1 - secchan/secchan.c | 2 -- 8 files changed, 21 insertions(+), 17 deletions(-) diff --git a/lib/ofp.c b/lib/ofp.c index b75681ec..6f9c878e 100644 --- a/lib/ofp.c +++ b/lib/ofp.c @@ -184,7 +184,7 @@ update_instruction_length(struct ofpbuf *buffer, size_t oia_offset) struct ofpbuf * make_flow_mod(uint8_t command, uint8_t table_id, - const struct flow *flow, size_t actions_len) + const struct flow *flow UNUSED, size_t actions_len) { struct ofp_flow_mod *ofm; size_t size = sizeof *ofm + actions_len; @@ -636,15 +636,16 @@ check_output_port(uint32_t port, int max_ports, bool table_allowed) static int check_setqueue_action(const union ofp_action *a, unsigned int len) { - const struct ofp_action_set_queue *oaq; + const struct ofp_action_set_queue *oaq UNUSED; int error; error = check_action_exact_len(a, len, 8); if (error) { return error; } - - oaq = (const struct ofp_action_set_queue *) a; + /*TODO check if this functions is relevant and finish or + remove it accordingly */ + /*oaq = (const struct ofp_action_set_queue *) a;*/ return 0; } diff --git a/lib/process.c b/lib/process.c index 38d3b022..d5d8df35 100644 --- a/lib/process.c +++ b/lib/process.c @@ -263,7 +263,10 @@ process_exited(struct process *p) return true; } else { char buf[_POSIX_PIPE_BUF]; - read(fds[0], buf, sizeof buf); + if (read(fds[0], buf, sizeof buf) != sizeof(buf)){ + fprintf(stderr, "read failed: %s\n", + strerror(errno)); + } return false; } } @@ -367,7 +370,10 @@ sigchld_handler(int signr UNUSED) } } } - write(fds[1], "", 1); + if (write(fds[1], "", 1) != 1){ + fprintf(stderr, "write failed: %s\n", + strerror(errno)); + } } static bool diff --git a/lib/queue.c b/lib/queue.c index 33e50067..24eb01d7 100644 --- a/lib/queue.c +++ b/lib/queue.c @@ -35,7 +35,6 @@ #include "queue.h" #include #include "compiler.h" -#include "leak-checker.h" #include "ofpbuf.h" static void check_queue(struct ofp_queue *q); @@ -91,7 +90,6 @@ void queue_push_tail(struct ofp_queue *q, struct ofpbuf *b) { check_queue(q); - leak_checker_claim(b); b->next = NULL; if (q->n++) { diff --git a/lib/signals.c b/lib/signals.c index 93327b1f..640e8750 100644 --- a/lib/signals.c +++ b/lib/signals.c @@ -115,7 +115,10 @@ bool signal_poll(struct signal *s) { char buf[_POSIX_PIPE_BUF]; - read(fds[0], buf, sizeof buf); + if (read(fds[0], buf, sizeof buf) != sizeof(buf)){ + fprintf(stderr, "read failed: %s\n", + strerror(errno)); + } if (signaled[s->signr]) { signaled[s->signr] = 0; return true; @@ -139,7 +142,10 @@ static void signal_handler(int signr) { if (signr >= 1 && signr < N_SIGNALS) { - write(fds[1], "", 1); + if (write(fds[1], "", 1) != 1){ + fprintf(stderr, "write failed: %s\n", + strerror(errno)); + } signaled[signr] = true; } } diff --git a/lib/vconn-ssl.c b/lib/vconn-ssl.c index 7f415a09..c802238f 100644 --- a/lib/vconn-ssl.c +++ b/lib/vconn-ssl.c @@ -48,7 +48,6 @@ #include #include #include "dynamic-string.h" -#include "leak-checker.h" #include "ofpbuf.h" #include "openflow/openflow.h" #include "packets.h" @@ -719,7 +718,6 @@ ssl_send(struct vconn *vconn, struct ofpbuf *buffer) ssl_clear_txbuf(sslv); return 0; case EAGAIN: - leak_checker_claim(buffer); ssl_register_tx_waiter(vconn); return 0; default: diff --git a/lib/vconn-stream.c b/lib/vconn-stream.c index 25a9eef0..f15dc892 100644 --- a/lib/vconn-stream.c +++ b/lib/vconn-stream.c @@ -40,7 +40,6 @@ #include #include #include -#include "leak-checker.h" #include "ofpbuf.h" #include "openflow/openflow.h" #include "poll-loop.h" @@ -214,7 +213,6 @@ stream_send(struct vconn *vconn, struct ofpbuf *buffer) ofpbuf_delete(buffer); return 0; } else if (retval >= 0 || errno == EAGAIN) { - leak_checker_claim(buffer); s->txbuf = buffer; if (retval > 0) { ofpbuf_pull(buffer, retval); diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index c6f68d87..0cd50363 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -7,7 +7,6 @@ VLOG_MODULE(dhcp_client) VLOG_MODULE(dpif) VLOG_MODULE(fault) VLOG_MODULE(flow) -VLOG_MODULE(leak_checker) VLOG_MODULE(learning_switch) VLOG_MODULE(mac_learning) VLOG_MODULE(netdev) diff --git a/secchan/secchan.c b/secchan/secchan.c index 3f67fdb2..43dbd441 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -49,7 +49,6 @@ #include "failover.h" #include "fault.h" #include "in-band.h" -#include "leak-checker.h" #include "list.h" #include "ofp.h" #include "ofpbuf.h" @@ -845,6 +844,5 @@ usage(void) printf("\nOther options:\n" " -h, --help display this help message\n" " -V, --version display version information\n"); - leak_checker_usage(); exit(EXIT_SUCCESS); } From 1cc549e6eda5c56f097c5253897ceac196e62aef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 12:07:43 +0000 Subject: [PATCH 135/191] Clean oflib warnings. This commit cleans the warnings found on oflib. Most of them are related to the variables print format. --- oflib/ofl-messages-print.c | 4 ---- oflib/ofl-structs-print.c | 26 ++++++++++++++------------ oflib/ofl-structs-unpack.c | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/oflib/ofl-messages-print.c b/oflib/ofl-messages-print.c index 09996dec..fd392791 100644 --- a/oflib/ofl-messages-print.c +++ b/oflib/ofl-messages-print.c @@ -674,18 +674,14 @@ ofl_msg_print_queue_get_config_reply(struct ofl_msg_queue_get_config_reply *msg, static void ofl_msg_print_role_msg(struct ofl_msg_role_request *msg, FILE *stream){ - fprintf(stream, "{role= %d, generation_id= %"PRIu64"}", msg->role, msg->generation_id); - } static void ofl_msg_print_async(struct ofl_msg_async_config* msg, FILE *stream){ - fprintf(stream, "{"); ofl_structs_async_config_print(stream, msg->config); fprintf(stream, "}"); - } char * diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index 6fd800ad..b521f6cc 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -391,28 +391,28 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) case OFPXMT_OFB_MPLS_LABEL: fprintf(stream, "mpls_label=\"%d\"",((uint32_t) *f->value) & 0x000fffff); break; - case OXM_OF_MPLS_TC: + case OFPXMT_OFB_MPLS_TC: fprintf(stream, "mpls_tc=\"%d\"", *f->value & 0x3); break; - case OXM_OF_MPLS_BOS: + case OFPXMT_OFB_MPLS_BOS: fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0x1); break; - case OXM_OF_METADATA: - fprintf(stream, "metadata=\"0x%llx\"", *((uint64_t*) f->value)); + case OFPXMT_OFB_METADATA: + fprintf(stream, "metadata=\"0x%"PRIu64"\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", metadata_mask=\"0x%"PRIx64"\"", *((uint64_t*)(f->value+8))); + fprintf(stream, ", metadata_mask=\"0x%"PRIu64"\"", *((uint64_t*)(f->value+8))); } break; - case OXM_OF_PBB_ISID : + case OFPXMT_OFB_PBB_ISID : fprintf(stream, "pbb_isid=\"%d\"", *((uint32_t*) f->value)); if (OXM_HASMASK(f->header)) { fprintf(stream, ", pbb_isid_mask=\"%x%x%x\"", (f->value+4)[0], (f->value+4)[1], (f->value+4)[2]); } break; case OFPXMT_OFB_TUNNEL_ID: - fprintf(stream, "tunnel_id=\"%"PRIu64"\"", *((uint64_t*) f->value)); + fprintf(stream, "tunnel_id=\"0x%"PRIu64"\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", tunnel_id_mask=\"%"PRIu64"\"", *((uint64_t*)(f->value+8))); + fprintf(stream, ", tunnel_id_mask=\"0x%"PRIu64"\"", *((uint64_t*)(f->value+8))); } break; case OFPXMT_OFB_IPV6_EXTHDR: @@ -517,15 +517,17 @@ ofl_structs_queue_prop_print(FILE *stream, struct ofl_queue_prop_header *p) { case (OFPQT_MIN_RATE): { struct ofl_queue_prop_min_rate *pm = (struct ofl_queue_prop_min_rate *)p; - fprintf(stream, "{rate=\"%u\"}", pm->rate); + fprintf(stream, "{min rate=\"%u\"}", pm->rate); break; } case (OFPQT_MAX_RATE): { - break; + struct ofl_queue_prop_max_rate *pm = (struct ofl_queue_prop_max_rate *)p; + + fprintf(stream, "{max rate=\"%u\"}", pm->rate); + break; } - case (OFPQT_EXPERIMENTER): { + case (OFPQT_EXPERIMENTER): break; - } } } diff --git a/oflib/ofl-structs-unpack.c b/oflib/ofl-structs-unpack.c index 17442af2..17adb633 100644 --- a/oflib/ofl-structs-unpack.c +++ b/oflib/ofl-structs-unpack.c @@ -193,7 +193,7 @@ ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct break; } default: - OFL_LOG_WARN(LOG_MODULE, "The received instruction type (%u) is invalid.", ntohs(src->type)); + OFL_LOG_WARN(LOG_MODULE, "The received instruction type (%d) is invalid.", ntohs(src->type)); return ofl_error(OFPET_BAD_INSTRUCTION, OFPBIC_UNKNOWN_INST); } From fe906b87ff8417d7267c402a5e4bee668736a0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 13:29:26 +0000 Subject: [PATCH 136/191] Delete wrong source files from lib/automake.mk --- lib/automake.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/automake.mk b/lib/automake.mk index 86e65195..9b50cf58 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -33,8 +33,6 @@ lib_libopenflow_a_SOURCES = \ lib/ipv6_util.h \ lib/list.c \ lib/list.h \ - lib/match.c \ - lib/match.c \ lib/mac-learning.c \ lib/mac-learning.h \ lib/netdev.c \ From 0c5eeed8ae4c1a9960722018bb8e96ec3b780760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 12:13:09 +0000 Subject: [PATCH 137/191] Fix secchan warnings. --- secchan/in-band.c | 2 +- secchan/secchan.c | 7 ++----- secchan/stp-secchan.c | 14 +++++++------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/secchan/in-band.c b/secchan/in-band.c index c3f6c5b7..2a8c1353 100644 --- a/secchan/in-band.c +++ b/secchan/in-band.c @@ -258,7 +258,7 @@ in_band_status_cb(struct status_reply *sr, void *in_band_) } void -get_ofp_packet_payload(struct ofp_packet_in *opi, struct ofpbuf *payload) +get_ofp_packet_payload(struct ofp_packet_in *opi UNUSED, struct ofpbuf *payload UNUSED) { //payload->data = opi->data; //payload->size = ntohs(opi->header.length) - offsetof(struct ofp_packet_in, diff --git a/secchan/secchan.c b/secchan/secchan.c index 43dbd441..12c4b0d3 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -343,10 +343,10 @@ get_ofp_packet_in(struct relay *r) return NULL; } -/* Need to adapt 1.2 packet-in changes */ +/* Need to adapt 1.3 packet-in changes */ bool get_ofp_packet_eth_header(struct relay *r, struct ofp_packet_in **opip, - struct eth_header **ethp) + struct eth_header **ethp UNUSED) { const int min_len = 0; //offsetof(struct ofp_packet_in, data) + ETH_HEADER_LEN; struct ofp_packet_in *opi = get_ofp_packet_in(r); @@ -599,7 +599,6 @@ parse_options(int argc, char *argv[], struct settings *s) {"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}, @@ -731,8 +730,6 @@ parse_options(int argc, char *argv[], struct settings *s) VLOG_OPTION_HANDLERS - LEAK_CHECKER_OPTION_HANDLERS - #ifdef HAVE_OPENSSL VCONN_SSL_OPTION_HANDLERS diff --git a/secchan/stp-secchan.c b/secchan/stp-secchan.c index 1567e286..3f717de2 100644 --- a/secchan/stp-secchan.c +++ b/secchan/stp-secchan.c @@ -64,7 +64,7 @@ static bool stp_local_packet_cb(struct relay *r, void *stp_) { struct ofpbuf *msg = r->halves[HALF_LOCAL].rxbuf; - struct ofp_header *oh; + struct ofp_header *oh UNUSED; struct stp_data *stp = stp_; struct ofp_packet_in *opi; struct eth_header *eth; @@ -74,13 +74,13 @@ stp_local_packet_cb(struct relay *r, void *stp_) struct flow flow; oh = msg->data; - /*if (oh->type == OFPT_FEATURES_REPLY - && msg->size >= offsetof(struct ofp_switch_features, ports)) { + /*if (oh->type == OFPT_FEATURES_REPLY*/ + /*&& msg->size >= offsetof(struct ofp_switch_features, ports)) {*/ /* TODO Zoltan: Temporarily removed when moving to Openflow 1.1 */ - /* struct ofp_switch_features *osf = msg->data; - osf->capabilities |= htonl(OFPC_STP); * - return false; - }*/ + /* 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)) { From 382feff7ee7cbf6abfc790332b21b562b2aa61aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 12:14:42 +0000 Subject: [PATCH 138/191] Fix unused function warning --- utilities/dpctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 851d5711..5dfb942b 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -179,7 +179,7 @@ static int parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val); static int -parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val, uint16_t *mask); +parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val, uint16_t *mask) UNUSED; static int parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val); From ef94441cf83335272a0ed93c9ef5e954d483599e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 12:39:03 +0000 Subject: [PATCH 139/191] Fixes warnings of the udatapath code. --- udatapath/action_set.c | 2 +- udatapath/datapath.c | 8 +++++--- udatapath/dp_ports.c | 9 ++++----- udatapath/group_entry.c | 10 +--------- udatapath/match_std.c | 2 +- udatapath/meter_table.c | 16 ++++++++-------- udatapath/pipeline.c | 2 +- udatapath/udatapath.c | 6 +++--- 8 files changed, 24 insertions(+), 31 deletions(-) diff --git a/udatapath/action_set.c b/udatapath/action_set.c index a72ec6df..601e2842 100644 --- a/udatapath/action_set.c +++ b/udatapath/action_set.c @@ -188,7 +188,7 @@ action_set_write_actions(struct action_set *set, for (i=0; idp_desc) == 0) { /* 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()); + char pid[10]; + gethostname(hostnametmp,sizeof hostnametmp); + sprintf(pid, "%u", getpid()); + snprintf(dp->dp_desc, strlen(hostnametmp) + 5 + strlen(pid),"%s pid=%s",hostnametmp, pid); } /* FIXME: Should not depend on udatapath_as_lib */ @@ -252,7 +254,7 @@ remote_rconn_run(struct datapath *dp, struct remote *r, uint8_t conn_id) { struct rconn *rconn = NULL; ofl_err error; size_t i; - + rconn = NULL; if (conn_id == MAIN_CONNECTION) rconn = r->rconn; else if (conn_id == PTIN_CONNECTION) diff --git a/udatapath/dp_ports.c b/udatapath/dp_ports.c index 77392864..db8fac3f 100644 --- a/udatapath/dp_ports.c +++ b/udatapath/dp_ports.c @@ -669,6 +669,7 @@ dp_ports_handle_port_mod(struct datapath *dp, struct ofl_msg_port_mod *msg, const struct sender *sender) { struct sw_port *p; + struct ofl_msg_port_status rep_msg; if(sender->remote->role == OFPCR_ROLE_SLAVE) return ofl_error(OFPET_BAD_REQUEST, OFPBRC_IS_SLAVE); @@ -693,12 +694,10 @@ dp_ports_handle_port_mod(struct datapath *dp, struct ofl_msg_port_mod *msg, } /*Notify all controllers that the port status has changed*/ - struct ofl_msg_port_status rep_msg = - {{.type = OFPT_PORT_STATUS}, - .reason = OFPPR_MODIFY, .desc = p->conf}; - + rep_msg.header.type = OFPT_PORT_STATUS; + rep_msg.reason = OFPPR_MODIFY; + rep_msg.desc = p->conf; dp_send_message(dp, (struct ofl_msg_header *)&rep_msg, NULL/*sender*/); - ofl_msg_free((struct ofl_msg_header *)msg, dp->exp); return 0; } diff --git a/udatapath/group_entry.c b/udatapath/group_entry.c index b50c8166..e5efb84e 100644 --- a/udatapath/group_entry.c +++ b/udatapath/group_entry.c @@ -83,20 +83,15 @@ struct group_entry * group_entry_create(struct datapath *dp, struct group_table *table, struct ofl_msg_group_mod *mod) { struct group_entry *entry; size_t i; - uint64_t now; - - now = time_msec(); + entry = xmalloc(sizeof(struct group_entry)); - entry->dp = dp; entry->table = table; - entry->desc = xmalloc(sizeof(struct ofl_group_desc_stats)); entry->desc->type = mod->type; entry->desc->group_id = mod->group_id; entry->desc->buckets_num = mod->buckets_num; entry->desc->buckets = mod->buckets; - entry->stats = xmalloc(sizeof(struct ofl_group_stats)); entry->stats->group_id = mod->group_id; entry->stats->ref_count = 0; @@ -112,7 +107,6 @@ group_entry_create(struct datapath *dp, struct group_table *table, struct ofl_ms entry->stats->counters[i]->packet_count = 0; entry->stats->counters[i]->byte_count = 0; } - switch (mod->type) { case (OFPGT_SELECT): { init_select_group(entry, mod); @@ -122,9 +116,7 @@ group_entry_create(struct datapath *dp, struct group_table *table, struct ofl_ms entry->data = NULL; } } - list_init(&entry->flow_refs); - return entry; } diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 35671dab..80d16553 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -164,6 +164,7 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ /* Loop over the flow entry's match fields */ HMAP_FOR_EACH(f, struct ofl_match_tlv, hmap_node, &flow_match->match_fields) { + char *f_str; /* Check presence of match field in packet */ has_mask = OXM_HASMASK(f->header); field_len = OXM_LENGTH(f->header); @@ -176,7 +177,6 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ packet_header |= field_len; flow_mask = f->value + field_len; } - /* Lookup the packet header */ packet_f = oxm_match_lookup(packet_header, packet); if (!packet_f) { diff --git a/udatapath/meter_table.c b/udatapath/meter_table.c index b2e7a12f..61c439ad 100644 --- a/udatapath/meter_table.c +++ b/udatapath/meter_table.c @@ -277,7 +277,7 @@ meter_table_handle_stats_request_meter_conf(struct meter_table *table, struct ofl_msg_multipart_meter_request *msg UNUSED, const struct sender *sender) { struct meter_entry *entry; - + struct ofl_msg_multipart_reply_meter_conf reply; if (msg->meter_id == OFPM_ALL) { entry = NULL; } else { @@ -288,13 +288,13 @@ meter_table_handle_stats_request_meter_conf(struct meter_table *table, } } - struct ofl_msg_multipart_reply_meter_conf reply = - {{{.type = OFPT_MULTIPART_REPLY}, - .type = OFPMP_METER_CONFIG, .flags = 0x0000}, - .stats_num = table->entries_num, - .stats = xmalloc(sizeof(struct ofl_meter_config *) * (msg->meter_id == OFPM_ALL ? table->entries_num : 1)) - }; - + reply.header.header.type = OFPT_MULTIPART_REPLY; + reply.header.type = OFPMP_METER_CONFIG; + reply.header.flags = 0x0000; + reply.stats_num = table->entries_num; + reply.stats = xmalloc(sizeof(struct ofl_meter_config *) * + (msg->meter_id == OFPM_ALL ? table->entries_num : 1)); + if (msg->meter_id == OFPM_ALL) { struct meter_entry *e; size_t i = 0; diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index bf925632..17b64ce5 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -634,7 +634,7 @@ execute_entry(struct pipeline *pl, struct flow_entry *entry, hmap_node, hash_int(OXM_OF_METADATA,0), &(*pkt)->handle_std->match.match_fields){ uint64_t *metadata = (uint64_t*) f->value; *metadata = (*metadata & ~wi->metadata_mask) | (wi->metadata & wi->metadata_mask); - VLOG_DBG_RL(LOG_MODULE, &rl, "Executing write metadata: %"PRIx64"", *metadata); + VLOG_DBG_RL(LOG_MODULE, &rl, "Executing write metadata: %"PRIu64"", *metadata); } break; } diff --git a/udatapath/udatapath.c b/udatapath/udatapath.c index 8484ef89..ab238aba 100644 --- a/udatapath/udatapath.c +++ b/udatapath/udatapath.c @@ -130,12 +130,12 @@ udatapath_cmd(int argc, char *argv[]) for (i = optind; i < argc; i += 2) { const char *pvconn_name = argv[i]; const char *pvconn_name_aux = NULL; - if (use_multiple_connections) - pvconn_name_aux = argv[i + 1]; - struct pvconn *pvconn, *pvconn_aux = NULL; int retval, retval_aux; + if (use_multiple_connections) + pvconn_name_aux = argv[i + 1]; + retval = pvconn_open(pvconn_name, &pvconn); if (!retval || retval == EAGAIN) { // Get another listener if we are using auxiliary connections From 0a89348bcf276c296175b7e68f05d61ff2d1b09b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 12:54:16 +0000 Subject: [PATCH 140/191] Fix ofp-read.c warnings --- utilities/ofp-read.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utilities/ofp-read.c b/utilities/ofp-read.c index eb18b577..6b95fe84 100644 --- a/utilities/ofp-read.c +++ b/utilities/ofp-read.c @@ -47,9 +47,10 @@ static size_t read_all(FILE *file, uint8_t **buf) rewind(file); data = (uint8_t*) malloc(buf_len); - fread(data, buf_len, 1, file); - if (ferror(file)) { - fprintf(stderr, "Cannot read msg file.\n"); + if (fread(data, buf_len, 1, file) != 1){ + if (ferror(file)) { + fprintf(stderr, "Cannot read msg file.\n"); + } return -1; } *buf = data; @@ -82,7 +83,6 @@ int main(int argc, char **argv) } buf_len = read_all(msg_file, &buf); buf0 = buf; - //printf("buf len = %ld\n", buf_len); while (buf_len > 0) { oh = (struct ofp_header *)buf; From c3e3d91b814c8862e6edbfa09cdac4dbebf89a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 13:41:59 +0000 Subject: [PATCH 141/191] No more compilation warnings. Remove a few remaining warnings. Moreover add to the Makefile the compilation flag -Werror to treat warnings as errors. --- Makefile.am | 2 +- lib/netdev.c | 1 + oflib/oxm-match.c | 6 +++--- udatapath/dp_ports.c | 4 ++-- udatapath/match_std.c | 1 - 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index bf2cf728..479d4aa9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ AM_CPPFLAGS = $(SSL_CFLAGS) -g AM_CPPFLAGS += -I $(top_srcdir)/include AM_CPPFLAGS += -I $(top_srcdir)/lib -AM_CFLAGS = -Wstrict-prototypes +AM_CFLAGS = -Wstrict-prototypes -Werror if NDEBUG AM_CPPFLAGS += -DNDEBUG diff --git a/lib/netdev.c b/lib/netdev.c index 58b9bfdc..3c40e8b9 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -742,6 +742,7 @@ do_open_netdev(const char *name, int ethertype, int tap_fd, uint32_t val; init_netdev(); *netdev_ = NULL; + netdev_fd = -1; netlink_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); diff --git a/oflib/oxm-match.c b/oflib/oxm-match.c index 36725be7..6e611288 100644 --- a/oflib/oxm-match.c +++ b/oflib/oxm-match.c @@ -512,15 +512,15 @@ parse_oxm_entry(struct ofl_match *match, const struct oxm_field *f, } case OFI_OXM_OF_PBB_ISID:{ uint8_t* pbb_isid; - pbb_isid = value; + pbb_isid = (uint8_t*) value; ofl_structs_match_put_pbb_isid(match, f->header, pbb_isid); return 0; } case OFI_OXM_OF_PBB_ISID_W:{ uint8_t* pbb_isid; uint8_t* pbb_isid_mask; - pbb_isid = value; - pbb_isid_mask = mask; + pbb_isid = (uint8_t*) value; + pbb_isid_mask = (uint8_t*) mask; if (check_bad_wildcard32(*((uint32_t*) value), *((uint32_t*) mask))){ return ofp_mkerr(OFPET_BAD_MATCH, OFPBMC_BAD_WILDCARDS); } diff --git a/udatapath/dp_ports.c b/udatapath/dp_ports.c index db8fac3f..d4e5b058 100644 --- a/udatapath/dp_ports.c +++ b/udatapath/dp_ports.c @@ -250,10 +250,10 @@ dp_ports_run(struct datapath *dp) { // find largest MTU on our interfaces // buffer is shared among all (idle) interfaces... - LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { + LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) { + const int mtu = netdev_get_mtu(p->netdev); if (IS_HW_PORT(p)) continue; - const int mtu = netdev_get_mtu(p->netdev); if (mtu > max_mtu) max_mtu = mtu; } diff --git a/udatapath/match_std.c b/udatapath/match_std.c index 80d16553..d9d1f8ad 100644 --- a/udatapath/match_std.c +++ b/udatapath/match_std.c @@ -164,7 +164,6 @@ packet_match(struct ofl_match *flow_match, struct ofl_match *packet){ /* Loop over the flow entry's match fields */ HMAP_FOR_EACH(f, struct ofl_match_tlv, hmap_node, &flow_match->match_fields) { - char *f_str; /* Check presence of match field in packet */ has_mask = OXM_HASMASK(f->header); field_len = OXM_LENGTH(f->header); From a8971892a34fce753026436fdd01b23a5131a85a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 4 Feb 2016 14:38:45 +0000 Subject: [PATCH 142/191] Implement some changes required by the change to the OF 1.3.5 header. The instruction header does not contain padding anymore so it was necessary to fix the count of instructions in the unpack function. --- oflib/ofl-messages-unpack.c | 47 ++++++++++++++++++++++--- oflib/ofl-structs-pack.c | 2 +- oflib/ofl-structs-unpack.c | 5 ++- oflib/ofl-structs.c | 68 ++++++++++++++++++------------------- udatapath/pipeline.c | 5 +-- 5 files changed, 80 insertions(+), 47 deletions(-) diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index c66e62dc..b58ae96e 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -52,6 +52,7 @@ OFL_LOG_INIT(LOG_MODULE) static ofl_err ofl_msg_unpack_error(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_error_msg *se; struct ofl_msg_error *de; @@ -78,6 +79,7 @@ ofl_msg_unpack_error(struct ofp_header *src, size_t *len, struct ofl_msg_header static ofl_err ofl_msg_unpack_echo(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofl_msg_echo *e = (struct ofl_msg_echo *)malloc(sizeof(struct ofl_msg_echo)); uint8_t *data; @@ -95,6 +97,7 @@ ofl_msg_unpack_echo(struct ofp_header *src, size_t *len, struct ofl_msg_header * static ofl_err ofl_msg_unpack_role_request(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_role_request *srl; struct ofl_msg_role_request *drl; @@ -116,6 +119,7 @@ ofl_msg_unpack_role_request(struct ofp_header *src, size_t *len, struct ofl_msg_ static ofl_err ofl_msg_unpack_features_reply(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_switch_features *sr; struct ofl_msg_features_reply *dr; @@ -141,6 +145,7 @@ ofl_msg_unpack_features_reply(struct ofp_header *src, size_t *len, struct ofl_ms static ofl_err ofl_msg_unpack_get_config_reply(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_switch_config *sr; struct ofl_msg_get_config_reply *dr; @@ -163,6 +168,7 @@ ofl_msg_unpack_get_config_reply(struct ofp_header *src, size_t *len, struct ofl_ static ofl_err ofl_msg_unpack_set_config(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_switch_config *sr; struct ofl_msg_set_config *dr; @@ -186,6 +192,7 @@ ofl_msg_unpack_set_config(struct ofp_header *src, size_t *len, struct ofl_msg_he static ofl_err ofl_msg_unpack_async_config(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg){ + struct ofp_async_config *sac; struct ofl_msg_async_config *dac; int i; @@ -196,7 +203,6 @@ ofl_msg_unpack_async_config(struct ofp_header *src, size_t *len, struct ofl_msg_ } *len -= sizeof(struct ofp_async_config); - sac = (struct ofp_async_config*)src; dac = (struct ofl_msg_async_config*)malloc(sizeof(struct ofl_msg_async_config)); dac->config = (struct ofl_async_config*) malloc(sizeof(struct ofl_async_config)); @@ -205,13 +211,13 @@ ofl_msg_unpack_async_config(struct ofp_header *src, size_t *len, struct ofl_msg_ dac->config->port_status_mask[i] = ntohl(sac->port_status_mask[i]); dac->config->flow_removed_mask[i] = ntohl(sac->flow_removed_mask[i]); } - *msg = (struct ofl_msg_header*)dac; return 0; } static ofl_err ofl_msg_unpack_packet_in(struct ofp_header *src, uint8_t* buf, size_t *len, struct ofl_msg_header **msg) { + struct ofp_packet_in *sp; struct ofl_msg_packet_in *dp; uint8_t *ptr; @@ -267,6 +273,7 @@ ofl_msg_unpack_packet_in(struct ofp_header *src, uint8_t* buf, size_t *len, stru static ofl_err ofl_msg_unpack_flow_removed(struct ofp_header *src,uint8_t *buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_flow_removed *sr; struct ofl_msg_flow_removed *dr; ofl_err error; @@ -319,6 +326,7 @@ ofl_msg_unpack_flow_removed(struct ofp_header *src,uint8_t *buf, size_t *len, st static ofl_err ofl_msg_unpack_port_status(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_port_status *ss; struct ofl_msg_port_status *ds; ofl_err error; @@ -346,6 +354,7 @@ ofl_msg_unpack_port_status(struct ofp_header *src, size_t *len, struct ofl_msg_h static ofl_err ofl_msg_unpack_packet_out(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_packet_out *sp; struct ofl_msg_packet_out *dp; struct ofp_action_header *act; @@ -424,6 +433,7 @@ ofl_msg_unpack_packet_out(struct ofp_header *src, size_t *len, struct ofl_msg_he static ofl_err ofl_msg_unpack_flow_mod(struct ofp_header *src,uint8_t* buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_flow_mod *sm; struct ofl_msg_flow_mod *dm; struct ofp_instruction *inst; @@ -492,6 +502,7 @@ ofl_msg_unpack_flow_mod(struct ofp_header *src,uint8_t* buf, size_t *len, struct static ofl_err ofl_msg_unpack_group_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_group_mod *sm; struct ofl_msg_group_mod *dm; struct ofp_bucket *bucket; @@ -570,7 +581,8 @@ ofl_msg_unpack_group_mod(struct ofp_header *src, size_t *len, struct ofl_msg_hea static ofl_err ofl_msg_unpack_meter_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { - struct ofp_meter_mod *sm; + + struct ofp_meter_mod *sm; struct ofl_msg_meter_mod *dm; struct ofp_meter_band_header *band; ofl_err error; @@ -631,6 +643,7 @@ ofl_msg_unpack_meter_mod(struct ofp_header *src, size_t *len, struct ofl_msg_hea static ofl_err ofl_msg_unpack_port_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_port_mod *sm; struct ofl_msg_port_mod *dm; @@ -665,6 +678,7 @@ ofl_msg_unpack_port_mod(struct ofp_header *src, size_t *len, struct ofl_msg_head static ofl_err ofl_msg_unpack_table_mod(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_table_mod *sm; struct ofl_msg_table_mod *dm; @@ -690,6 +704,7 @@ ofl_msg_unpack_table_mod(struct ofp_header *src, size_t *len, struct ofl_msg_hea static ofl_err ofl_msg_unpack_multipart_request_flow(struct ofp_multipart_request *os, uint8_t* buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_flow_stats_request *sm; struct ofl_msg_multipart_request_flow *dm; ofl_err error = 0; @@ -730,6 +745,7 @@ ofl_msg_unpack_multipart_request_flow(struct ofp_multipart_request *os, uint8_t* static ofl_err ofl_msg_unpack_multipart_request_port(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_port_stats_request *sm; struct ofl_msg_multipart_request_port *dm; @@ -760,6 +776,7 @@ ofl_msg_unpack_multipart_request_port(struct ofp_multipart_request *os, size_t * static ofl_err ofl_msg_unpack_multipart_request_empty(struct ofp_multipart_request *os UNUSED, size_t *len, struct ofl_msg_header **msg) { + // ofp_multipart_request length was checked at ofl_msg_unpack_multipart_request len -= sizeof(struct ofp_multipart_request); @@ -769,11 +786,11 @@ ofl_msg_unpack_multipart_request_empty(struct ofp_multipart_request *os UNUSED, static ofl_err ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp){ + struct ofl_msg_multipart_request_table_features *dm; ofl_err error; uint8_t *features; size_t i; - dm = (struct ofl_msg_multipart_request_table_features*) malloc(sizeof(struct ofl_msg_multipart_request_table_features)); if (!(*len)){ dm->tables_num = 0; @@ -806,6 +823,7 @@ ofl_msg_unpack_multipart_request_table_features(struct ofp_multipart_request *os static ofl_err ofl_msg_unpack_multipart_request_queue(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_queue_stats_request *sm; struct ofl_msg_multipart_request_queue *dm; @@ -836,6 +854,7 @@ ofl_msg_unpack_multipart_request_queue(struct ofp_multipart_request *os, size_t static ofl_err ofl_msg_unpack_multipart_request_group(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_group_stats_request *sm; struct ofl_msg_multipart_request_group *dm; @@ -858,6 +877,7 @@ ofl_msg_unpack_multipart_request_group(struct ofp_multipart_request *os, size_t static ofl_err ofl_msg_unpack_meter_multipart_request(struct ofp_multipart_request *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_meter_multipart_request *sm; struct ofl_msg_multipart_meter_request *dm; @@ -880,6 +900,7 @@ ofl_msg_unpack_meter_multipart_request(struct ofp_multipart_request *os, size_t static ofl_err ofl_msg_unpack_multipart_request(struct ofp_header *src,uint8_t *buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofl_msg_multipart_request_header *ofls; struct ofp_multipart_request *os; int error; @@ -970,6 +991,7 @@ ofl_msg_unpack_multipart_request(struct ofp_header *src,uint8_t *buf, size_t *le static ofl_err ofl_msg_unpack_reply_desc(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_desc *sm; struct ofl_msg_reply_desc *dm; @@ -995,6 +1017,7 @@ ofl_msg_unpack_reply_desc(struct ofp_multipart_reply *os, size_t *len, struct of static ofl_err ofl_msg_unpack_multipart_reply_flow(struct ofp_multipart_reply *os, uint8_t *buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_flow_stats *stat; struct ofl_msg_multipart_reply_flow *dm; ofl_err error; @@ -1033,6 +1056,7 @@ ofl_msg_unpack_multipart_reply_flow(struct ofp_multipart_reply *os, uint8_t *buf static ofl_err ofl_msg_unpack_multipart_reply_aggregate(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_aggregate_stats_reply *sm; struct ofl_msg_multipart_reply_aggregate *dm; @@ -1057,6 +1081,7 @@ ofl_msg_unpack_multipart_reply_aggregate(struct ofp_multipart_reply *os, size_t static ofl_err ofl_msg_unpack_multipart_reply_table(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_table_stats *stat; struct ofl_msg_multipart_reply_table *dm; ofl_err error; @@ -1090,6 +1115,7 @@ ofl_msg_unpack_multipart_reply_table(struct ofp_multipart_reply *os, size_t *len static ofl_err ofl_msg_unpack_multipart_reply_port(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_port_stats *stat = (struct ofp_port_stats *)os->body; struct ofl_msg_multipart_reply_port *dm = (struct ofl_msg_multipart_reply_port *) malloc(sizeof(struct ofl_msg_multipart_reply_port)); ofl_err error; @@ -1123,6 +1149,7 @@ ofl_msg_unpack_multipart_reply_port(struct ofp_multipart_reply *os, size_t *len, static ofl_err ofl_msg_unpack_multipart_reply_queue(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_queue_stats *stat = (struct ofp_queue_stats *)os->body; struct ofl_msg_multipart_reply_queue *dm = (struct ofl_msg_multipart_reply_queue *) malloc(sizeof(struct ofl_msg_multipart_reply_queue)); ofl_err error; @@ -1154,6 +1181,7 @@ ofl_msg_unpack_multipart_reply_queue(struct ofp_multipart_reply *os, size_t *len static ofl_err ofl_msg_unpack_multipart_reply_group(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_group_stats *stat; struct ofl_msg_multipart_reply_group *dm; ofl_err error; @@ -1188,6 +1216,7 @@ ofl_msg_unpack_multipart_reply_group(struct ofp_multipart_reply *os, size_t *len static ofl_err ofl_msg_unpack_multipart_reply_group_desc(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofp_group_desc_stats *stat; struct ofl_msg_multipart_reply_group_desc *dm; ofl_err error; @@ -1222,6 +1251,7 @@ ofl_msg_unpack_multipart_reply_group_desc(struct ofp_multipart_reply *os, size_t static ofl_err ofl_msg_unpack_multipart_reply_group_features(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_group_features *sm; struct ofl_msg_multipart_reply_group_features *dm; int i; @@ -1247,6 +1277,7 @@ ofl_msg_unpack_multipart_reply_group_features(struct ofp_multipart_reply *os, si static ofl_err ofl_msg_unpack_multipart_reply_table_features(struct ofp_multipart_reply *src, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp){ + struct ofl_msg_multipart_reply_table_features *dm; int i; ofl_err error; @@ -1278,6 +1309,7 @@ ofl_msg_unpack_multipart_reply_table_features(struct ofp_multipart_reply *src, s static ofl_err ofl_msg_unpack_multipart_reply_meter_stats(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_meter_stats *stat; struct ofl_msg_multipart_reply_meter *dm; ofl_err error; @@ -1312,6 +1344,7 @@ ofl_msg_unpack_multipart_reply_meter_stats(struct ofp_multipart_reply *os, size_ static ofl_err ofl_msg_unpack_multipart_reply_meter_config(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg){ + struct ofp_meter_config *conf; struct ofl_msg_multipart_reply_meter_conf *dm; ofl_err error; @@ -1346,6 +1379,7 @@ ofl_msg_unpack_multipart_reply_meter_config(struct ofp_multipart_reply *os, size static ofl_err ofl_msg_unpack_multipart_reply_port_desc(struct ofp_multipart_reply *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_port *port; struct ofl_msg_multipart_reply_port_desc *pd; ofl_err error; @@ -1376,6 +1410,7 @@ ofl_msg_unpack_multipart_reply_port_desc(struct ofp_multipart_reply *src, size_t static ofl_err ofl_msg_unpack_multipart_reply_meter_features(struct ofp_multipart_reply *os, size_t *len, struct ofl_msg_header **msg) { + struct ofp_meter_features *src; struct ofl_msg_multipart_reply_meter_features *dst; @@ -1401,6 +1436,7 @@ ofl_msg_unpack_multipart_reply_meter_features(struct ofp_multipart_reply *os, si static ofl_err ofl_msg_unpack_multipart_reply(struct ofp_header *src, uint8_t *buf, size_t *len, struct ofl_msg_header **msg, struct ofl_exp *exp) { + struct ofl_msg_multipart_reply_header *ofls; struct ofp_multipart_reply *os; int error; @@ -1495,6 +1531,7 @@ ofl_msg_unpack_multipart_reply(struct ofp_header *src, uint8_t *buf, size_t *len static ofl_err ofl_msg_unpack_queue_get_config_request(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_queue_get_config_request *sr; struct ofl_msg_queue_get_config_request *dr; @@ -1521,6 +1558,7 @@ ofl_msg_unpack_queue_get_config_request(struct ofp_header *src, size_t *len, str static ofl_err ofl_msg_unpack_queue_get_config_reply(struct ofp_header *src, size_t *len, struct ofl_msg_header **msg) { + struct ofp_queue_get_config_reply *sr; struct ofl_msg_queue_get_config_reply *dr; struct ofp_packet_queue *queue; @@ -1564,6 +1602,7 @@ ofl_msg_unpack_queue_get_config_reply(struct ofp_header *src, size_t *len, struc static ofl_err ofl_msg_unpack_empty(struct ofp_header *src UNUSED, size_t *len, struct ofl_msg_header **msg) { + // ofp_header length was checked at ofl_msg_unpack *len -= sizeof(struct ofp_header); diff --git a/oflib/ofl-structs-pack.c b/oflib/ofl-structs-pack.c index 7291af03..a829f908 100644 --- a/oflib/ofl-structs-pack.c +++ b/oflib/ofl-structs-pack.c @@ -126,7 +126,7 @@ ofl_structs_instructions_pack(struct ofl_instruction_header *src, struct ofp_ins struct ofp_instruction_actions *di = (struct ofp_instruction_actions *)dst; total_len = sizeof(struct ofp_instruction_actions) + ofl_actions_ofp_total_len(si->actions, si->actions_num, exp); - + di->len = htons(total_len); memset(di->pad, 0x00, 4); data = (uint8_t *)dst + sizeof(struct ofp_instruction_actions); diff --git a/oflib/ofl-structs-unpack.c b/oflib/ofl-structs-unpack.c index 17adb633..e088a441 100644 --- a/oflib/ofl-structs-unpack.c +++ b/oflib/ofl-structs-unpack.c @@ -49,12 +49,12 @@ ofl_err ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct ofl_instruction_header **dst, struct ofl_exp *exp) { size_t ilen; struct ofl_instruction_header *inst = NULL; - + if (*len < sizeof(struct ofp_instruction)) { OFL_LOG_WARN(LOG_MODULE, "Received instruction is too short (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); } - + if (*len < ntohs(src->len)) { OFL_LOG_WARN(LOG_MODULE, "Received instruction has invalid length (set to %u, but only %zu received).", ntohs(src->len), *len); return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_LEN); @@ -498,7 +498,6 @@ ofl_structs_flow_stats_unpack(struct ofp_flow_stats *src, uint8_t *buf, size_t * OFL_LOG_WARN(LOG_MODULE, "Received flow stats has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); } - if (*len < ntohs(src->length)) { OFL_LOG_WARN(LOG_MODULE, "Received flow stats reply has invalid length (set to %u, but only %zu received).", ntohs(src->length), *len); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); diff --git a/oflib/ofl-structs.c b/oflib/ofl-structs.c index cc6144c0..efae08fe 100644 --- a/oflib/ofl-structs.c +++ b/oflib/ofl-structs.c @@ -50,7 +50,6 @@ ofl_utils_count_ofp_table_features_properties(void *data, size_t data_len, size_ struct ofp_table_feature_prop_header *prop; uint8_t *d; - d = (uint8_t*) data; *count = 0; while (data_len >= sizeof(struct ofp_table_feature_prop_header)){ @@ -68,9 +67,9 @@ ofl_utils_count_ofp_table_features_properties(void *data, size_t data_len, size_ ofl_err ofl_utils_count_ofp_table_features(void *data, size_t data_len, size_t *count){ + struct ofp_table_features *feature; uint8_t *d; - d = (uint8_t*) data; *count = 0; while (data_len >= sizeof(struct ofp_table_features)){ @@ -90,37 +89,33 @@ ofl_utils_count_ofp_table_features(void *data, size_t data_len, size_t *count){ ofl_err ofl_utils_count_ofp_instructions(void *data, size_t data_len, size_t *count) { + struct ofp_instruction *inst; uint8_t *d; - d = (uint8_t *)data; *count = 0; /* this is needed so that buckets are handled correctly */ - while (data_len >= sizeof(struct ofp_instruction)- 4) { + while (data_len > sizeof(struct ofp_instruction)) { inst = (struct ofp_instruction *)d; if (data_len < ntohs(inst->len) || ntohs(inst->len) < sizeof(struct ofp_instruction) - 4) { OFL_LOG_WARN(LOG_MODULE, "Received instruction has invalid length."); return ofl_error(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); - } data_len -= ntohs(inst->len); d += ntohs(inst->len); (*count)++; - } - return 0; } ofl_err ofl_utils_count_ofp_buckets(void *data, size_t data_len, size_t *count) { + struct ofp_bucket *bucket; uint8_t *d; - d = (uint8_t *)data; *count = 0; - while (data_len >= sizeof(struct ofp_bucket)) { bucket = (struct ofp_bucket *)d; @@ -132,19 +127,17 @@ ofl_utils_count_ofp_buckets(void *data, size_t data_len, size_t *count) { d += ntohs(bucket->len); (*count)++; } - return 0; } ofl_err ofl_utils_count_ofp_meter_bands(void *data, size_t data_len, size_t *count) { + struct ofp_meter_band_header *mb; uint8_t *d; - d = (uint8_t *)data; *count = 0; - while (data_len >= sizeof(struct ofp_meter_band_header)) { mb = (struct ofp_meter_band_header *)d; @@ -156,12 +149,12 @@ ofl_utils_count_ofp_meter_bands(void *data, size_t data_len, size_t *count) { d += ntohs(mb->len); (*count)++; } - return 0; } ofl_err ofl_utils_count_ofp_ports(void *data UNUSED, size_t data_len, size_t *count) { + *count = data_len / sizeof(struct ofp_port); return 0; } @@ -169,12 +162,11 @@ ofl_utils_count_ofp_ports(void *data UNUSED, size_t data_len, size_t *count) { ofl_err ofl_utils_count_ofp_packet_queues(void *data, size_t data_len, size_t *count) { + struct ofp_packet_queue *queue; uint8_t *d; - d = (uint8_t *)data; *count = 0; - while (data_len >= sizeof(struct ofp_packet_queue)) { queue = (struct ofp_packet_queue *)d; @@ -186,16 +178,14 @@ ofl_utils_count_ofp_packet_queues(void *data, size_t data_len, size_t *count) { d += ntohs(queue->len); (*count)++; } - return 0; - } ofl_err ofl_utils_count_ofp_flow_stats(void *data, size_t data_len, size_t *count) { + struct ofp_flow_stats *stat; uint8_t *d; - d = (uint8_t *)data; *count = 0; while (data_len >= sizeof(struct ofp_flow_stats)) { @@ -208,18 +198,16 @@ ofl_utils_count_ofp_flow_stats(void *data, size_t data_len, size_t *count) { d += ntohs(stat->length); (*count)++; } - return 0; } ofl_err ofl_utils_count_ofp_group_stats(void *data, size_t data_len, size_t *count) { + struct ofp_group_stats *stat; uint8_t *d; - d = (uint8_t *)data; *count = 0; - while (data_len >= sizeof(struct ofp_group_stats)) { stat = (struct ofp_group_stats *)d; @@ -231,44 +219,45 @@ ofl_utils_count_ofp_group_stats(void *data, size_t data_len, size_t *count) { d += ntohs(stat->length); (*count)++; } - return 0; } ofl_err ofl_utils_count_ofp_table_stats(void *data UNUSED, size_t data_len, size_t *count) { + *count = data_len / sizeof(struct ofp_table_stats); return 0; - } ofl_err ofl_utils_count_ofp_bucket_counters(void *data UNUSED, size_t data_len, size_t *count) { + *count = data_len / sizeof(struct ofp_bucket_counter); return 0; } ofl_err ofl_utils_count_ofp_port_stats(void *data UNUSED, size_t data_len, size_t *count) { + *count = data_len / sizeof(struct ofp_port_stats); return 0; } ofl_err ofl_utils_count_ofp_queue_stats(void *data UNUSED, size_t data_len, size_t *count) { + *count = data_len / sizeof(struct ofp_queue_stats); return 0; } ofl_err ofl_utils_count_ofp_group_desc_stats(void *data UNUSED, size_t data_len, size_t *count) { + struct ofp_group_desc_stats *stat; uint8_t *d; - d = (uint8_t *)data; *count = 0; - while (data_len >= sizeof(struct ofp_group_desc_stats)) { stat = (struct ofp_group_desc_stats *)d; @@ -280,18 +269,15 @@ ofl_utils_count_ofp_group_desc_stats(void *data UNUSED, size_t data_len, size_t d += ntohs(stat->length); (*count)++; } - return 0; } ofl_err -ofl_utils_count_ofp_queue_props(void *data, size_t data_len, size_t *count) { +ofl_utils_count_ofp_queue_props(void *data, size_t data_len, size_t *count) { struct ofp_queue_prop_header *prop; uint8_t *d; - d = (uint8_t *)data; (*count) = 0; - while (data_len >= sizeof(struct ofp_queue_prop_header)) { prop = (struct ofp_queue_prop_header *)d; @@ -303,15 +289,14 @@ ofl_utils_count_ofp_queue_props(void *data, size_t data_len, size_t *count) { d += ntohs(prop->len); (*count)++; } - return 0; } ofl_err ofl_utils_count_ofp_meter_stats(void *data, size_t data_len, size_t *count){ + struct ofp_meter_stats *stats; uint8_t *d; - d = (uint8_t *)data; (*count) = 0; @@ -331,11 +316,10 @@ ofl_utils_count_ofp_meter_stats(void *data, size_t data_len, size_t *count){ ofl_err ofl_utils_count_ofp_meter_band_stats(void *data, size_t data_len, size_t *count){ - uint8_t *d; + uint8_t *d; d = (uint8_t *)data; (*count) = 0; - while (data_len >= sizeof(struct ofp_meter_band_stats)) { if (data_len < sizeof(struct ofp_meter_band_stats)) { @@ -351,12 +335,11 @@ ofl_utils_count_ofp_meter_band_stats(void *data, size_t data_len, size_t *count) ofl_err ofl_utils_count_ofp_meter_config(void *data, size_t data_len, size_t *count){ + struct ofp_meter_config *config; uint8_t *d; - d = (uint8_t *)data; (*count) = 0; - while (data_len >= sizeof(struct ofp_meter_config)) { config = (struct ofp_meter_config *)d; if (data_len < ntohs(config->length) || ntohs(config->length) < sizeof(struct ofp_meter_config)) { @@ -373,11 +356,13 @@ ofl_utils_count_ofp_meter_config(void *data, size_t data_len, size_t *count){ void ofl_structs_free_packet_queue(struct ofl_packet_queue *queue) { OFL_UTILS_FREE_ARR(queue->properties, queue->properties_num); + free(queue); } void ofl_structs_free_instruction(struct ofl_instruction_header *inst, struct ofl_exp *exp) { + switch (inst->type) { case OFPIT_GOTO_TABLE: case OFPIT_WRITE_METADATA: @@ -406,16 +391,19 @@ ofl_structs_free_instruction(struct ofl_instruction_header *inst, struct ofl_exp } void ofl_structs_free_meter_bands(struct ofl_meter_band_header *meter_band){ + free(meter_band); } void ofl_structs_free_meter_band_stats(struct ofl_meter_band_stats* s){ + free(s); } void ofl_structs_free_meter_stats(struct ofl_meter_stats *stats){ + OFL_UTILS_FREE_ARR_FUN(stats->band_stats, stats->meter_bands_num, ofl_structs_free_meter_band_stats); free(stats); @@ -423,6 +411,7 @@ ofl_structs_free_meter_stats(struct ofl_meter_stats *stats){ void ofl_structs_free_meter_config(struct ofl_meter_config *conf){ + OFL_UTILS_FREE_ARR_FUN(conf->bands, conf->meter_bands_num, ofl_structs_free_meter_bands); free(conf); @@ -430,11 +419,13 @@ ofl_structs_free_meter_config(struct ofl_meter_config *conf){ void ofl_structs_free_table_stats(struct ofl_table_stats *stats) { + free(stats); } void ofl_structs_free_bucket(struct ofl_bucket *bucket, struct ofl_exp *exp) { + OFL_UTILS_FREE_ARR_FUN2(bucket->actions, bucket->actions_num, ofl_actions_free, exp); free(bucket); @@ -443,6 +434,7 @@ ofl_structs_free_bucket(struct ofl_bucket *bucket, struct ofl_exp *exp) { void ofl_structs_free_flow_stats(struct ofl_flow_stats *stats, struct ofl_exp *exp) { + OFL_UTILS_FREE_ARR_FUN2(stats->instructions, stats->instructions_num, ofl_structs_free_instruction, exp); ofl_structs_free_match(stats->match, exp); @@ -451,18 +443,21 @@ ofl_structs_free_flow_stats(struct ofl_flow_stats *stats, struct ofl_exp *exp) { void ofl_structs_free_port(struct ofl_port *port) { + free(port->name); free(port); } void ofl_structs_free_group_stats(struct ofl_group_stats *stats) { + OFL_UTILS_FREE_ARR(stats->counters, stats->counters_num); free(stats); } void ofl_structs_free_group_desc_stats(struct ofl_group_desc_stats *stats, struct ofl_exp *exp) { + OFL_UTILS_FREE_ARR_FUN2(stats->buckets, stats->buckets_num, ofl_structs_free_bucket, exp); free(stats); @@ -470,6 +465,7 @@ ofl_structs_free_group_desc_stats(struct ofl_group_desc_stats *stats, struct ofl void ofl_structs_free_table_features(struct ofl_table_features* features, struct ofl_exp *exp){ + /* We sometime sets it to NULL (see set feature request). Jean II */ if (features == NULL) return; @@ -482,6 +478,7 @@ ofl_structs_free_table_features(struct ofl_table_features* features, struct ofl_ void ofl_structs_free_table_properties(struct ofl_table_feature_prop_header *prop, struct ofl_exp *exp UNUSED){ + switch(prop->type){ case (OFPTFPT_INSTRUCTIONS): case (OFPTFPT_INSTRUCTIONS_MISS):{ @@ -519,6 +516,7 @@ ofl_structs_free_table_properties(struct ofl_table_feature_prop_header *prop, st void ofl_structs_free_match(struct ofl_match_header *match, struct ofl_exp *exp) { + switch (match->type) { case (OFPMT_OXM): { if (match->length > sizeof(struct ofp_match)){ diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index 17b64ce5..ad6ea765 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -64,21 +64,18 @@ struct pipeline * pipeline_create(struct datapath *dp) { struct pipeline *pl; int i; - pl = xmalloc(sizeof(struct pipeline)); for (i=0; itables[i] = flow_table_create(dp, i); } pl->dp = dp; - + nblink_initialize(); return pl; } static bool is_table_miss(struct flow_entry *entry){ - return ((entry->stats->priority) == 0 && (entry->match->length <= 4)); - } /* Sends a packet to the controller in a packet_in message */ From 1996e7b56a81dda4c61fa248dd5d4042bc562ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 25 Feb 2016 22:15:39 +0000 Subject: [PATCH 143/191] Enables execution of boot.sh in non git respositories. This commit fixes a common execution problem of boot.sh. The script expected a git repository to generate the Debian distribution files automake. However, when the code is downloaded from Github as a zip file, it does not comes as a git repository. For this reason, now there is a check to avoid errors when building code from the zip. --- boot.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/boot.sh b/boot.sh index 97921fac..284e4695 100755 --- a/boot.sh +++ b/boot.sh @@ -3,12 +3,18 @@ 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 +if [ -d .git ]; then + (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 +else + (echo '# Automatically generated by boot.sh (from ls).' && + printf 'EXTRA_DIST += \\\n' && + ls debian | grep -v '^debian/\.gitignore$' | + sed -e 's/^/debian\//' -e 's/\(.*\)/ \1 \\/' -e '$s/ \\//') > debian/automake.mk +fi cat debian/control.in > debian/control - # Bootstrap configure system from .ac/.am files autoreconf --install --force From 9557f68a7d75154c015595cee2673b0fe9363e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Fri, 1 Jul 2016 14:45:09 +0200 Subject: [PATCH 144/191] Statement about the current state of the switch --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c86e2197..322d7399 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,10 @@ This is an [OpenFlow 1.3][ofp13] compatible user-space software switch implementation. The code is based on the [Ericsson TrafficLab 1.1 softswitch implementation][ericssonsw11], with changes in the forwarding plane to support -OpenFlow 1.3. +OpenFlow 1.3. + +**Important notice:** Despite the fact the switch is still popular for adventurers trying to implement own changes to OpenFlow, support now is on a best-effort base. Currently, there are lots of complaints about performance degradation, broken features and installation problems. Although not confirmed, most of the problems seem to be due to most recent linux versions. As the main contributor of the switch, I would like to keep the project alive and fix all the recurrent issues. However, life moves and new projects come, resulting in no time to work on it. I am still happy to help anyone who comes asking for advice on how to make changes in the code, but I cannot guarantee quick and active replies. + *-Eder* The following components are available in this package: * `ofdatapath`: the switch implementation @@ -129,8 +132,8 @@ code from the original Stanford switch). # Acknowledgments -This project is supported by Ericsson Innovation Center in Brazil. -Maintained by CPqD in technical collaboration with Ericsson Research. +This project was supported by Ericsson Innovation Center in Brazil. +Formerly maintained by CPqD in technical collaboration with Ericsson Research. **Contributions:** From 26a561cb374723b918778b61f3142caf7c1b3228 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Thu, 27 Oct 2016 16:57:45 -0200 Subject: [PATCH 145/191] Fix missing set_field=tunn_id: option in dpctl. This commit fixes the dpctl utility, including the option to set the tunnel id field on flow_mod commands. According to the OpenFlow specification 1.3.5, "The pipeline field OXM_OF_TUNNEL_ID is valid in the set-field action, other pipeline fields, OXM_OF_IN_PORT, OXM_OF_IN_PHY_PORT and OXM_OF_METADATA are not valid in the set- field action". --- utilities/dpctl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 5dfb942b..2d821c95 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -1877,6 +1877,19 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { } return 0; } + /* Tunnel ID */ + if (strncmp(token, MATCH_TUNNEL_ID KEY_VAL2, strlen(MATCH_TUNNEL_ID KEY_VAL2)) == 0) { + uint64_t *tunn_id = malloc(sizeof(uint64_t)); + if (sscanf(token, MATCH_TUNNEL_ID KEY_VAL2 "0x%"SCNx64"", (tunn_id)) != 1) { + ofp_fatal(0, "Error parsing %s: %s.", MATCH_TUNNEL_ID, token); + } + else { + act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); + act->field->header = OXM_OF_TUNNEL_ID; + act->field->value = (uint8_t*) tunn_id; + } + return 0; + } ofp_fatal(0, "Error parsing set_field arg: %s.", token); } From 1ae53df1c5dd2457d7fab439e1831fc4c7e4b706 Mon Sep 17 00:00:00 2001 From: ederlf Date: Tue, 21 Feb 2017 17:29:17 +0000 Subject: [PATCH 146/191] Update README with information about the BEBA-EU branch. --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 322d7399..c631c85e 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,12 @@ This is an [OpenFlow 1.3][ofp13] compatible user-space software switch implement implementation][ericssonsw11], with changes in the forwarding plane to support OpenFlow 1.3. +**UPDATE**: A new experimental branch with contributions from the [BEBA EU Project][beba-eu] is available with lots of performance improvements and OpenFlow extensions. If you want to try the code checkout to the BEBA-EU branch. + + ``` + $ git checkout remotes/origin/BEBA-EU + ``` + **Important notice:** Despite the fact the switch is still popular for adventurers trying to implement own changes to OpenFlow, support now is on a best-effort base. Currently, there are lots of complaints about performance degradation, broken features and installation problems. Although not confirmed, most of the problems seem to be due to most recent linux versions. As the main contributor of the switch, I would like to keep the project alive and fix all the recurrent issues. However, life moves and new projects come, resulting in no time to work on it. I am still happy to help anyone who comes asking for advice on how to make changes in the code, but I cannot guarantee quick and active replies. *-Eder* @@ -162,3 +168,4 @@ E-mail: Eder Leao Fernandes (ederleaofernandes at gmail . com) [ofp13]: https://www.opennetworking.org/images/stories/downloads/specification/openflow-spec-v1.3.0.pdf [ericssonsw11]: https://github.com/TrafficLab/of11softswitch [compileubuntu14]: http://tocai.dia.uniroma3.it/compunet-wiki/index.php/Installing_and_setting_up_OpenFlow_tools +[beba-eu]: http://www.beba-project.eu/ From 136cc080f7de9cdd1c9e867e4e233a3db2ee16a5 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Tue, 14 Mar 2017 17:07:40 -0300 Subject: [PATCH 147/191] Fix some mismatch on print format strings. This commit fix some mismatch on print format strings. Some strings were indicating hex but the variable were being printed as decimal, and vice versa. --- oflib/ofl-structs-print.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index b521f6cc..fafb3e4d 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -398,9 +398,9 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) fprintf(stream, "mpls_bos=\"%d\"", *f->value & 0x1); break; case OFPXMT_OFB_METADATA: - fprintf(stream, "metadata=\"0x%"PRIu64"\"", *((uint64_t*) f->value)); + fprintf(stream, "metadata=\"0x%"PRIx64"\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", metadata_mask=\"0x%"PRIu64"\"", *((uint64_t*)(f->value+8))); + fprintf(stream, ", metadata_mask=\"0x%"PRIx64"\"", *((uint64_t*)(f->value+8))); } break; case OFPXMT_OFB_PBB_ISID : @@ -410,9 +410,9 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) } break; case OFPXMT_OFB_TUNNEL_ID: - fprintf(stream, "tunnel_id=\"0x%"PRIu64"\"", *((uint64_t*) f->value)); + fprintf(stream, "tunnel_id=\"0x%"PRIx64"\"", *((uint64_t*) f->value)); if (OXM_HASMASK(f->header)) { - fprintf(stream, ", tunnel_id_mask=\"0x%"PRIu64"\"", *((uint64_t*)(f->value+8))); + fprintf(stream, ", tunnel_id_mask=\"0x%"PRIx64"\"", *((uint64_t*)(f->value+8))); } break; case OFPXMT_OFB_IPV6_EXTHDR: @@ -856,7 +856,7 @@ ofl_structs_table_features_print(FILE *stream, struct ofl_table_features *s){ fprintf(stream, "{table=\""); ofl_table_print(stream, s->table_id); fprintf(stream, "\", name=\"%s\", " - "metadata_match=\"%"PRIx64"\", metadata_write=\"%"PRIx64"\", config=\"%"PRIu32"\"," + "metadata_match=\"0x%"PRIx64"\", metadata_write=\"0x%"PRIx64"\", config=\"%"PRIu32"\"," "max_entries=\"%"PRIu32"\"", s->name, s->metadata_match, s->metadata_write, s->config, s->max_entries); for(i =0; i < s->properties_num; i++){ From b85b534a48b40a26ecae9a2d2e1f4792ba91cfc6 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Sat, 18 Mar 2017 15:57:58 -0300 Subject: [PATCH 148/191] This commit fix other mismatch on print format strings. Some strings were indicating hex but the variable were being printed as decimal, and vice versa. --- oflib/ofl-messages-print.c | 2 +- oflib/ofl-structs-print.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/oflib/ofl-messages-print.c b/oflib/ofl-messages-print.c index fd392791..0a40bb2e 100644 --- a/oflib/ofl-messages-print.c +++ b/oflib/ofl-messages-print.c @@ -205,7 +205,7 @@ ofl_msg_print_meter_mod(struct ofl_msg_meter_mod *msg, FILE *stream) { fprintf(stream,"{cmd=\""); ofl_meter_mod_command_print(stream, msg->command); fprintf(stream, "\", flags=\"0x%"PRIx16"\"",msg->flags); - fprintf(stream, "\", meter_id=\"%"PRIx32"\"",msg->meter_id); + fprintf(stream, "\", meter_id=\"%"PRIu32"\"",msg->meter_id); fprintf(stream,"\", bands=["); for (i=0; imeter_bands_num; i++) { diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index fafb3e4d..1dfc8eed 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -729,8 +729,8 @@ ofl_structs_meter_features_to_string(struct ofl_meter_features* s){ void ofl_structs_meter_features_print(FILE *stream, struct ofl_meter_features* s){ - fprintf(stream, "{max_meter=\"%"PRIu32"\", band_types=\"%"PRIx32"\"," - "capabilities =\"%"PRIx32"\", max_bands = %u , max_color = %u", + fprintf(stream, "{max_meter=\"%"PRIu32"\", band_types=\"0x%"PRIx32"\"," + "capabilities =\"0x%"PRIx32"\", max_bands = %u , max_color = %u", s->max_meter, s->band_types, s->capabilities, s->max_bands, s->max_color); fprintf(stream, "}"); From 8cb8d7c51fe19051b8cf8f256c8ec438d420745a Mon Sep 17 00:00:00 2001 From: nikchez01 Date: Wed, 31 May 2017 06:30:04 +0530 Subject: [PATCH 149/191] dpctl queue-get-config is showing only 1 queue. Even if multiple queues are configured, dpctl shows only 1 queue. The proposed change will work as long as structure size of ofp_queue_prop_min_rate, ofp_queue_prop_max_rate and ofp_queue_prop_experimenter remains same. Also, I am working on patch after which dpctl will support max-rate setting also. Currently it supports min-rate settings only. Please review. --- oflib/ofl-messages-unpack.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index b58ae96e..bd9a7397 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -1564,6 +1564,7 @@ ofl_msg_unpack_queue_get_config_reply(struct ofp_header *src, size_t *len, struc struct ofp_packet_queue *queue; ofl_err error; size_t i; + size_t len1=0,len2=0; if (*len < sizeof(struct ofp_queue_get_config_reply)) { OFL_LOG_WARN(LOG_MODULE, "Received GET_CONFIG_REPLY has invalid length (%zu).", *len); @@ -1585,6 +1586,10 @@ ofl_msg_unpack_queue_get_config_reply(struct ofp_header *src, size_t *len, struc queue = sr->queues; for (i = 0; i < dr->queues_num; i++) { + /* This is so that it can parse packet with more than 1 queue. + * Previously, dpctl was showing only 1 queue even if more than 1 queues are configured. */ + len1=*len-(sizeof(struct ofp_packet_queue)+sizeof(struct ofp_queue_prop_min_rate))*((int)dr->queues_num-1-i); + len2=*len-(sizeof(struct ofp_packet_queue)+sizeof(struct ofp_queue_prop_min_rate))*((int)dr->queues_num-1-i); error = ofl_structs_packet_queue_unpack(queue, len, &(dr->queues[i])); if (error) { OFL_UTILS_FREE_ARR_FUN(dr->queues, i, @@ -1592,6 +1597,7 @@ ofl_msg_unpack_queue_get_config_reply(struct ofp_header *src, size_t *len, struc free (dr); return error; } + *len-=len2-len1; //This is so that it can parse packet with more than 1 queue. queue = (struct ofp_packet_queue *)((uint8_t *)queue + ntohs(queue->len)); } From 3fafe8b2a4b2619506274fc4ba655ac1b9eb7c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 10 Jul 2017 10:58:45 +0100 Subject: [PATCH 150/191] Update installation instructions. --- README.md | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c631c85e..f5ed26da 100644 --- a/README.md +++ b/README.md @@ -35,34 +35,28 @@ The switch makes use of the NetBee library to parse packets, so we need to insta $ sudo apt-get install cmake libpcap-dev libxerces-c2-dev libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev ``` -2. Download the most recent Netbee version, and unpack the source code from:http://www.nbee.org/download/nbeesrc-jan-10-2013.php - -3. Create the build system +2. Clone and build netbee ``` + $ git clone https://github.com/netgroup-polito/netbee.git $ cd nbeesrc/src $ cmake . - ``` - -4. Compile - - ``` $ make ``` -5. Add the shared libraries built in `/nbeesrc/bin/` to your `/usr/local/lib` directory +3. Add the shared libraries built in `/nbeesrc/bin/` to your `/usr/local/lib` directory ``` $ sudo cp ../bin/libn*.so /usr/local/lib ``` -6. Run `ldconfig` +4. Run `ldconfig` ``` $ sudo ldconfig ``` -7. Put the contens of folder `nbeesrc/include` in the `/usr/include` +5. Put the contens of folder `nbeesrc/include` in the `/usr/include` ``` $ sudo cp -R ../include/* /usr/include/ From c12f71eda640dcc11486c8998c7ed9d717e40115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 10 Jul 2017 21:54:21 +0100 Subject: [PATCH 151/191] Update list of packages required. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f5ed26da..5d49c1e5 100644 --- a/README.md +++ b/README.md @@ -32,14 +32,14 @@ The switch makes use of the NetBee library to parse packets, so we need to insta 1. Install the following packages: ``` - $ sudo apt-get install cmake libpcap-dev libxerces-c2-dev libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev + $ sudo apt-get install cmake libpcap-dev install libxerces-c3.1 libxerces-c-dev libpcre3 libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev ``` 2. Clone and build netbee ``` $ git clone https://github.com/netgroup-polito/netbee.git - $ cd nbeesrc/src + $ cd netbee/src $ cmake . $ make ``` From 3689341679d09e6fb0a50a31daef0c17df1e0033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 10 Jul 2017 21:55:43 +0100 Subject: [PATCH 152/191] Remove paragraph about building in Ubuntu 14.04 --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 5d49c1e5..2c72408a 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,7 @@ The following components are available in this package: # Getting Started -These instructions have been tested on Ubuntu 12.04. Other distributions or versions may need different steps. - -For Ubuntu 14.04, please check @castroflavio solution: -[How to compile on Ubuntu 14.04][compileubuntu14] +These instructions have been tested on Ubuntu 16.04. Other distributions or versions may need different steps. ## Before building The switch makes use of the NetBee library to parse packets, so we need to install it first. From 7c55475a460cf476a5aabb840ed6c4e49dca68e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 10 Jul 2017 22:15:03 +0100 Subject: [PATCH 153/191] Remove spurious install word among the dependencies --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c72408a..dddcff19 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ The switch makes use of the NetBee library to parse packets, so we need to insta 1. Install the following packages: ``` - $ sudo apt-get install cmake libpcap-dev install libxerces-c3.1 libxerces-c-dev libpcre3 libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev + $ sudo apt-get install cmake libpcap-dev libxerces-c3.1 libxerces-c-dev libpcre3 libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev ``` 2. Clone and build netbee From 8937c1ba28bce381e4dcd08e2f1847e51fd96408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 10 Jul 2017 22:34:40 +0100 Subject: [PATCH 154/191] Add install script --- install.sh | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100755 install.sh diff --git a/install.sh b/install.sh new file mode 100755 index 00000000..160c3a7d --- /dev/null +++ b/install.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Script to install on most recent versions of Ubuntu +# Tested on the LTS versions 14.04 and 16.04. +# Feel free to contribute to additional systems + +UBUNTU_DEPS="cmake libpcap-dev libxerces-c3.1 libxerces-c-dev libpcre3 libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev" + +install_deps() +{ + if [ $(lsb_release -si) = "Ubuntu" ]; then + sudo apt-get install $UBUNTU_DEPS + fi +} + +install_nbee() +{ + git clone https://github.com/netgroup-polito/netbee.git + cd netbee/src + cmake . + make + cd .. + sudo cp bin/libn*.so /usr/local/lib + sudo ldconfig + sudo cp -R include/* /usr/include/ + cd .. +} + +switch() +{ + ./boot.sh + ./configure + make + sudo make install +} + +install_deps +install_nbee +switch \ No newline at end of file From ec4b19eeb61511603bccb985920172da98df9b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 10 Jul 2017 23:13:51 +0100 Subject: [PATCH 155/191] Add compiler dependencies --- install.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 160c3a7d..b8d23864 100755 --- a/install.sh +++ b/install.sh @@ -4,8 +4,9 @@ # Tested on the LTS versions 14.04 and 16.04. # Feel free to contribute to additional systems -UBUNTU_DEPS="cmake libpcap-dev libxerces-c3.1 libxerces-c-dev libpcre3 libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev" +UBUNTU_DEPS="g++ gcc cmake libc6-dev libpcap-dev libxerces-c3.1 libxerces-c-dev libpcre3 libpcre3-dev flex bison pkg-config autoconf libtool libboost-dev" +BUILD_DIR="$(pwd -P)" install_deps() { if [ $(lsb_release -si) = "Ubuntu" ]; then @@ -23,11 +24,11 @@ install_nbee() sudo cp bin/libn*.so /usr/local/lib sudo ldconfig sudo cp -R include/* /usr/include/ - cd .. } switch() { + cd $BUILD_DIR ./boot.sh ./configure make From f06181c2f55c6daa96b1a068bbb414d142c5cf32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 10 Jul 2017 23:23:00 +0100 Subject: [PATCH 156/191] Execute install.sh from other directories --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index b8d23864..dc88b57d 100755 --- a/install.sh +++ b/install.sh @@ -28,7 +28,7 @@ install_nbee() switch() { - cd $BUILD_DIR + cd $BUILD_DIR/ofsoftswitch13 ./boot.sh ./configure make From 59bc59caa7f7b8ccc78f738afc1c950f87ba6836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 10 Jul 2017 23:45:00 +0100 Subject: [PATCH 157/191] Fix when build dir is the same of the code --- install.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index dc88b57d..97d93282 100755 --- a/install.sh +++ b/install.sh @@ -27,8 +27,12 @@ install_nbee() } switch() -{ - cd $BUILD_DIR/ofsoftswitch13 +{ + if [ ${BUILD_DIR##*/} != "ofsoftswitch13" ]; then + cd $BUILD_DIR/ofsoftswitch13 + else + cd $BUILD_DIR + fi ./boot.sh ./configure make From e4322f5fb5ec63f0feaf2ae5ea231251ee3108fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Mon, 10 Jul 2017 23:58:23 +0100 Subject: [PATCH 158/191] Add check for directory of netbee --- install.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 97d93282..154c4fb9 100755 --- a/install.sh +++ b/install.sh @@ -16,7 +16,9 @@ install_deps() install_nbee() { - git clone https://github.com/netgroup-polito/netbee.git + if [ ! -d "netbee" ]; then + git clone https://github.com/netgroup-polito/netbee.git + fi cd netbee/src cmake . make From 2f8112083f143e35c4d990163fe49f4923b05fa6 Mon Sep 17 00:00:00 2001 From: Matthieu Coudron Date: Sun, 20 May 2018 05:26:39 +0900 Subject: [PATCH 159/191] compiles with gcc 7.3.0 Fixes 2/3 errors when compiling with gcc 7.3.0; for instance secchan/ratelimit.c: In function 'rate_limit_local_packet_cb': secchan/ratelimit.c:86:34: error: array subscript is above array bounds [-Werror=array-bounds] for (q = &rl->queues[0]; q < &rl->queues[OFPP_MAX]; q++) { --- lib/backtrace.c | 2 +- oflib/oxm-match.c | 10 ---------- secchan/ratelimit.c | 2 +- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/lib/backtrace.c b/lib/backtrace.c index 8a56561f..2661f904 100644 --- a/lib/backtrace.c +++ b/lib/backtrace.c @@ -116,7 +116,7 @@ backtrace_capture(struct backtrace *backtrace) size_t n; n = 0; - for (frame = __builtin_frame_address(1); + for (frame = __builtin_frame_address(0); frame != NULL && in_stack(frame) && frame[0] != NULL && n < BACKTRACE_MAX_FRAMES; frame = frame[0]) diff --git a/oflib/oxm-match.c b/oflib/oxm-match.c index 6e611288..31d26cfe 100644 --- a/oflib/oxm-match.c +++ b/oflib/oxm-match.c @@ -67,16 +67,6 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); -/* Possible masks for TLV OXM_ETH_DST_W. */ -static const uint8_t eth_all_0s[ETH_ADDR_LEN] - = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t eth_all_1s[ETH_ADDR_LEN] - = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -static const uint8_t eth_mcast_1[ETH_ADDR_LEN] - = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; -static const uint8_t eth_mcast_0[ETH_ADDR_LEN] - = {0xfe, 0xff, 0xff, 0xff, 0xff, 0xff}; - struct oxm_field all_fields[NUM_OXM_FIELDS] = { #define DEFINE_FIELD(HEADER, DL_TYPES, NW_PROTO, MASKABLE) \ { HMAP_NODE_NULL_INITIALIZER, OFI_OXM_##HEADER, OXM_##HEADER, \ diff --git a/secchan/ratelimit.c b/secchan/ratelimit.c index 6992387f..f147bff5 100644 --- a/secchan/ratelimit.c +++ b/secchan/ratelimit.c @@ -83,7 +83,7 @@ drop_packet(struct rate_limiter *rl) longest = &rl->queues[0]; n_longest = 1; - for (q = &rl->queues[0]; q < &rl->queues[OFPP_MAX]; q++) { + for (q = &rl->queues[0]; q < &rl->queues[65535]; q++) { if (longest->n < q->n) { longest = q; n_longest = 1; From 70fe1882a893cc901ed9e676fb1322d87f48899e Mon Sep 17 00:00:00 2001 From: ederlf Date: Thu, 24 May 2018 08:27:13 +0000 Subject: [PATCH 160/191] Fix mpls label printing --- oflib/ofl-structs-print.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index 1dfc8eed..71ef0984 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -389,7 +389,7 @@ ofl_structs_oxm_tlv_print(FILE *stream, struct ofl_match_tlv *f) fprintf(stream, "icmpv6_code=\"%d\"", *f->value); break; case OFPXMT_OFB_MPLS_LABEL: - fprintf(stream, "mpls_label=\"%d\"",((uint32_t) *f->value) & 0x000fffff); + fprintf(stream, "mpls_label=\"%d\"",*((uint32_t*) f->value) & 0x000fffff); break; case OFPXMT_OFB_MPLS_TC: fprintf(stream, "mpls_tc=\"%d\"", *f->value & 0x3); From 2187ece3530963b9f88d2cbbf9d13b63dc8a3b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Daube?= Date: Sun, 10 Jun 2018 22:24:44 +0200 Subject: [PATCH 161/191] Add to set_field in dpctl: UDP source / destination port --- utilities/dpctl.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 2d821c95..a7837f5b 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -1831,7 +1831,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { if (strncmp(token, MATCH_TP_DST KEY_VAL2, strlen(MATCH_TP_DST KEY_VAL2)) == 0) { uint16_t* tp_dst = xmalloc(2); if (parse16(token + strlen(MATCH_TP_DST KEY_VAL2), NULL, 0, 0xffff, tp_dst)) { - ofp_fatal(0, "Error parsing tcp_src: %s.", token); + ofp_fatal(0, "Error parsing tcp_dst: %s.", token); }else{ act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); act->field->header = OXM_OF_TCP_DST; @@ -1839,6 +1839,28 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { } return 0; } + if (strncmp(token, MATCH_UDP_SRC KEY_VAL2, strlen(MATCH_UDP_SRC KEY_VAL2)) == 0) { + uint16_t* udp_src = xmalloc(2); + if (parse16(token+ strlen(MATCH_UDP_SRC KEY_VAL2), NULL, 0, 0xffff, udp_src)) { + ofp_fatal(0, "Error parsing udp_src: %s.", token); + }else{ + act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); + act->field->header = OXM_OF_UDP_SRC; + act->field->value = (uint8_t*) udp_src; + } + return 0; + } + if (strncmp(token, MATCH_UDP_DST KEY_VAL2, strlen(MATCH_UDP_DST KEY_VAL2)) == 0) { + uint16_t* udp_dst = xmalloc(2); + if (parse16(token+ strlen(MATCH_UDP_DST KEY_VAL2), NULL, 0, 0xffff, udp_dst)) { + ofp_fatal(0, "Error parsing udp_dst: %s.", token); + }else{ + act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); + act->field->header = OXM_OF_UDP_DST; + act->field->value = (uint8_t*) udp_dst; + } + return 0; + } if (strncmp(token, MATCH_NW_SRC_IPV6 KEY_VAL2 , strlen(MATCH_NW_SRC_IPV6 KEY_VAL2)) == 0) { struct in6_addr *addr = (struct in6_addr*) malloc(sizeof(struct in6_addr)); struct in6_addr mask; From 6c9673d7f12dcfd77da0399058c49003c07f2c6c Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Thu, 12 Jul 2018 09:29:05 -0300 Subject: [PATCH 162/191] Fix incorrect bitwise comparison when checking port configuration. --- udatapath/dp_ports.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/udatapath/dp_ports.c b/udatapath/dp_ports.c index d4e5b058..ded2fe12 100644 --- a/udatapath/dp_ports.c +++ b/udatapath/dp_ports.c @@ -215,7 +215,7 @@ static void process_buffer(struct datapath *dp, struct sw_port *p, struct ofpbuf *buffer) { struct packet *pkt; - if (p->conf->config & ((OFPPC_NO_RECV | OFPPC_PORT_DOWN) != 0)) { + if ((p->conf->config & (OFPPC_NO_RECV | OFPPC_PORT_DOWN)) != 0) { ofpbuf_delete(buffer); return; } From 4f52e14a9af0903eb5cb05414dfc5bccdbefa875 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Tue, 24 Jul 2018 22:55:14 -0300 Subject: [PATCH 163/191] Dpctl: check for values in hexadecimal for 8, 16 and 32 bits. --- utilities/dpctl.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 2d821c95..dfbdb506 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -2619,8 +2619,15 @@ parse8(char *str, struct names8 *names, size_t names_num, uint8_t max, uint8_t * } } - if ((max > 0) && (sscanf(str, "%"SCNu8"", val)) == 1 && ((*val) <= max)) { - return 0; + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + if ((max > 0) && (sscanf(str, "%"SCNx8"", val)) == 1 && (*val <= max)) { + return 0; + } + } else { + if ((max > 0) && (sscanf(str, "%"SCNu8"", val)) == 1 && (*val <= max)) { + return 0; + } } return -1; } @@ -2636,16 +2643,15 @@ parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16 } } - /* Checks if the passed value is hexadecimal. */ - if( str[1] == 'x'){ - if ((max > 0) && (sscanf(str, "%"SCNx16"", val)) == 1 && (*val <= max)) { + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + if ((max > 0) && (sscanf(str, "%"SCNx16"", val)) == 1 && (*val <= max)) { return 0; } - } - else { - if ((max > 0) && (sscanf(str, "%"SCNu16"", val)) == 1 && (*val <= max)) { + } else { + if ((max > 0) && (sscanf(str, "%"SCNu16"", val)) == 1 && (*val <= max)) { return 0; - } + } } return -1; } @@ -2689,8 +2695,15 @@ parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32 } } - if ((max > 0) && (sscanf(str, "%"SCNu32"", val)) == 1 && ((*val) <= max)) { - return 0; + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + if ((max > 0) && (sscanf(str, "%"SCNx32"", val)) == 1 && (*val <= max)) { + return 0; + } + } else { + if ((max > 0) && (sscanf(str, "%"SCNu32"", val)) == 1 && (*val <= max)) { + return 0; + } } return -1; } From ca0f4f3d81dc227a54cb42ed4e7f2bb545ab7090 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Wed, 25 Jul 2018 00:56:41 -0300 Subject: [PATCH 164/191] Fix parse16m and parse32m functions. Parse16m is not used. Parse32m is used only for MATCH_IPV6_FLABEL. This commit fixes current implementation that is not working. It can now parse both decimal and hexadecimal values and masks. --- utilities/dpctl.c | 71 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index dfbdb506..5eccb839 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -179,7 +179,7 @@ static int parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val); static int -parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val, uint16_t *mask) UNUSED; +parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val, uint16_t **mask) UNUSED; static int parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val); @@ -2657,28 +2657,44 @@ parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16 } static int -parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val, uint16_t *mask){ +parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16_t *val, uint16_t **mask){ size_t i; - char *token, *saveptr = NULL; + int read; + char *saveptr = NULL; for (i=0; i 0) && (*val <= max)) { - if (!sscanf(str, "%"SCNu16"", val)) - return -1; + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + read = sscanf(str, "%"SCNx16"", val); + } else { + read = sscanf(str, "%"SCNu16"", val); + } + if ((read == 0) || (max == 0) || (*val > max)) { + return -1; } - token = strtok_r(str, MASK_SEP, &saveptr); - if(token == NULL) - mask = NULL; - else { - mask = (uint16_t*) malloc(sizeof(uint16_t)); - sscanf(token, "%"SCNu16"", mask); + strtok_r(str, MASK_SEP, &saveptr); + if (strcmp (saveptr, "") == 0) { + *mask = NULL; + return 0; + } + *mask = (uint16_t*) malloc(sizeof(uint16_t)); + + /* Checks for mask in hexadecimal. */ + if (saveptr[0] == '0' && saveptr[1] == 'x') { + read = sscanf(saveptr, "%"SCNx16"", *mask); + } else { + read = sscanf(saveptr, "%"SCNu16"", *mask); + } + if (read == 0) { + return -1; } return 0; @@ -2712,26 +2728,41 @@ static int parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val, uint32_t **mask){ size_t i; + int read; char *saveptr = NULL; for (i=0; i 0) && (*val <= max)) { - if (!sscanf(str, "%"SCNu32"", val)) - return -1; + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + read = sscanf(str, "%"SCNx32"", val); + } else { + read = sscanf(str, "%"SCNu32"", val); + } + if ((read == 0) || (max == 0) || (*val > max)) { + return -1; } strtok_r(str, MASK_SEP, &saveptr); - - if(saveptr == NULL) + if (strcmp (saveptr, "") == 0) { *mask = NULL; - else { - *mask = (uint32_t*) malloc(sizeof(uint32_t)); - sscanf(saveptr, "%"SCNu32"", *mask); + return 0; + } + *mask = (uint32_t*) malloc(sizeof(uint32_t)); + + /* Checks for mask in hexadecimal. */ + if (saveptr[0] == '0' && saveptr[1] == 'x') { + read = sscanf(saveptr, "%"SCNx32"", *mask); + } else { + read = sscanf(saveptr, "%"SCNu32"", *mask); + } + if (read == 0) { + return -1; } return 0; } From 6c5fa417d58bb828e774cccd667c2fe346e737ef Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Wed, 25 Jul 2018 00:49:27 -0300 Subject: [PATCH 165/191] Fix memory leak erros when parsing masks. --- utilities/dpctl.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 5eccb839..265ea077 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -1141,8 +1141,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put_eth(m,OXM_OF_ETH_SRC,eth_src); - else + else { ofl_structs_match_put_eth_m(m,OXM_OF_ETH_SRC_W,eth_src,mask); + free(mask); + } } continue; } @@ -1155,8 +1157,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put_eth(m,OXM_OF_ETH_DST,eth_dst); - else + else { ofl_structs_match_put_eth_m(m,OXM_OF_ETH_DST_W,eth_dst, mask); + free(mask); + } } continue; } @@ -1170,8 +1174,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put_eth(m, OXM_OF_ARP_SHA, arp_sha); - else + else { ofl_structs_match_put_eth_m(m, OXM_OF_ARP_SHA_W, arp_sha, mask); + free(mask); + } } continue; } @@ -1184,8 +1190,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put_eth(m,OXM_OF_ARP_THA, arp_tha); - else + else { ofl_structs_match_put_eth_m(m,OXM_OF_ARP_THA_W, arp_tha, mask); + free(mask); + } } continue; } @@ -1198,8 +1206,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put32(m, OXM_OF_ARP_SPA,arp_src); - else + else { ofl_structs_match_put32m(m, OXM_OF_ARP_SPA_W, arp_src, *mask); + free(mask); + } } continue; } @@ -1212,8 +1222,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put32(m, OXM_OF_ARP_TPA, arp_target); - else + else { ofl_structs_match_put32m(m, OXM_OF_ARP_TPA_W, arp_target, *mask); + free(mask); + } } continue; } @@ -1299,8 +1311,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put32(m, OXM_OF_IPV4_SRC,nw_src); - else + else { ofl_structs_match_put32m(m, OXM_OF_IPV4_SRC_W, nw_src, *mask); + free(mask); + } } continue; } @@ -1313,8 +1327,10 @@ parse_match(char *str, struct ofl_match_header **match) { else { if (mask == NULL) ofl_structs_match_put32(m, OXM_OF_IPV4_DST,nw_dst); - else + else { ofl_structs_match_put32m(m, OXM_OF_IPV4_DST_W,nw_dst, *mask); + free(mask); + } } continue; } @@ -1461,8 +1477,10 @@ parse_match(char *str, struct ofl_match_header **match) { else if(mask == NULL) ofl_structs_match_put32(m, OXM_OF_IPV6_FLABEL, ipv6_label); - else + else { ofl_structs_match_put32m(m, OXM_OF_IPV6_FLABEL_W, ipv6_label, *mask); + free (mask); + } continue; } From a5d4f7c47711f9fce615539b9317085949a95146 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Wed, 25 Jul 2018 01:37:39 -0300 Subject: [PATCH 166/191] Fix missing 0x% before SCNx* --- utilities/dpctl.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 265ea077..d74393b1 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -2639,7 +2639,7 @@ parse8(char *str, struct names8 *names, size_t names_num, uint8_t max, uint8_t * /* Checks for value in hexadecimal. */ if (str[0] == '0' && str[1] == 'x') { - if ((max > 0) && (sscanf(str, "%"SCNx8"", val)) == 1 && (*val <= max)) { + if ((max > 0) && (sscanf(str, "0x%"SCNx8"", val)) == 1 && (*val <= max)) { return 0; } } else { @@ -2663,7 +2663,7 @@ parse16(char *str, struct names16 *names, size_t names_num, uint16_t max, uint16 /* Checks for value in hexadecimal. */ if (str[0] == '0' && str[1] == 'x') { - if ((max > 0) && (sscanf(str, "%"SCNx16"", val)) == 1 && (*val <= max)) { + if ((max > 0) && (sscanf(str, "0x%"SCNx16"", val)) == 1 && (*val <= max)) { return 0; } } else { @@ -2690,7 +2690,7 @@ parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint1 /* Checks for value in hexadecimal. */ if (str[0] == '0' && str[1] == 'x') { - read = sscanf(str, "%"SCNx16"", val); + read = sscanf(str, "0x%"SCNx16"", val); } else { read = sscanf(str, "%"SCNu16"", val); } @@ -2707,7 +2707,7 @@ parse16m(char *str, struct names16 *names, size_t names_num, uint16_t max, uint1 /* Checks for mask in hexadecimal. */ if (saveptr[0] == '0' && saveptr[1] == 'x') { - read = sscanf(saveptr, "%"SCNx16"", *mask); + read = sscanf(saveptr, "0x%"SCNx16"", *mask); } else { read = sscanf(saveptr, "%"SCNu16"", *mask); } @@ -2731,7 +2731,7 @@ parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32 /* Checks for value in hexadecimal. */ if (str[0] == '0' && str[1] == 'x') { - if ((max > 0) && (sscanf(str, "%"SCNx32"", val)) == 1 && (*val <= max)) { + if ((max > 0) && (sscanf(str, "0x%"SCNx32"", val)) == 1 && (*val <= max)) { return 0; } } else { @@ -2758,7 +2758,7 @@ parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint3 /* Checks for value in hexadecimal. */ if (str[0] == '0' && str[1] == 'x') { - read = sscanf(str, "%"SCNx32"", val); + read = sscanf(str, "0x%"SCNx32"", val); } else { read = sscanf(str, "%"SCNu32"", val); } @@ -2775,7 +2775,7 @@ parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint3 /* Checks for mask in hexadecimal. */ if (saveptr[0] == '0' && saveptr[1] == 'x') { - read = sscanf(saveptr, "%"SCNx32"", *mask); + read = sscanf(saveptr, "0x%"SCNx32"", *mask); } else { read = sscanf(saveptr, "%"SCNu32"", *mask); } From 46c32fa829ae914bfa83002dcd9f5ba80f1f24a0 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Wed, 25 Jul 2018 01:53:44 -0300 Subject: [PATCH 167/191] New parse64m for parsing metadata and tunnel id masks in match fields. --- utilities/dpctl.c | 63 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index d74393b1..71418bf6 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -187,6 +187,9 @@ parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32 static int parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val, uint32_t **mask); +static int +parse64m(char *str, uint64_t max, uint64_t *val, uint64_t **mask); + static void set_table_features_match(struct vconn *vconn, int argc, char *argv[]); @@ -1541,10 +1544,17 @@ parse_match(char *str, struct ofl_match_header **match) { /* Metadata */ if (strncmp(token, MATCH_METADATA KEY_VAL, strlen(MATCH_METADATA KEY_VAL)) == 0) { uint64_t metadata; - if (sscanf(token, MATCH_METADATA KEY_VAL "0x%"SCNx64"", (&metadata)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", MATCH_METADATA, token); + uint64_t *mask; + if (parse64m(token + strlen(MATCH_METADATA KEY_VAL), 0xffffffffffffffffULL, &metadata, &mask)) { + ofp_fatal(0, "Error parsing meta: %s.", token); } - else ofl_structs_match_put64(m, OXM_OF_METADATA, metadata); + else + if(mask == NULL) + ofl_structs_match_put64(m, OXM_OF_METADATA, metadata); + else { + ofl_structs_match_put64m(m, OXM_OF_METADATA_W, metadata, *mask); + free (mask); + } continue; } /*PBB ISID*/ @@ -1559,10 +1569,17 @@ parse_match(char *str, struct ofl_match_header **match) { /* Tunnel ID */ if (strncmp(token, MATCH_TUNNEL_ID KEY_VAL, strlen(MATCH_TUNNEL_ID KEY_VAL)) == 0) { uint64_t tunn_id; - if (sscanf(token, MATCH_TUNNEL_ID KEY_VAL "0x%"SCNx64"", (&tunn_id)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", MATCH_TUNNEL_ID, token); + uint64_t *mask; + if (parse64m(token + strlen(MATCH_TUNNEL_ID KEY_VAL), 0xffffffffffffffffULL, &tunn_id, &mask)) { + ofp_fatal(0, "Error parsing tunn_id: %s.", token); } - else ofl_structs_match_put64(m, OXM_OF_TUNNEL_ID, tunn_id); + else + if(mask == NULL) + ofl_structs_match_put64(m, OXM_OF_TUNNEL_ID, tunn_id); + else { + ofl_structs_match_put64m(m, OXM_OF_TUNNEL_ID_W, tunn_id, *mask); + free (mask); + } continue; } /*Extension Headers */ @@ -2785,6 +2802,40 @@ parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint3 return 0; } +static int +parse64m(char *str, uint64_t max, uint64_t *val, uint64_t **mask) { + int read; + char *saveptr = NULL; + + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + read = sscanf(str, "0x%"SCNx64"", val); + } else { + read = sscanf(str, "%"SCNu64"", val); + } + if ((read == 0) || (max == 0) || (*val > max)) { + return -1; + } + + strtok_r(str, MASK_SEP, &saveptr); + if (strcmp (saveptr, "") == 0) { + *mask = NULL; + return 0; + } + *mask = (uint64_t*) malloc(sizeof(uint64_t)); + + /* Checks for mask in hexadecimal. */ + if (saveptr[0] == '0' && saveptr[1] == 'x') { + read = sscanf(saveptr, "0x%"SCNx64"", *mask); + } else { + read = sscanf(saveptr, "%"SCNu64"", *mask); + } + if (read == 0) { + return -1; + } + return 0; +} + struct oxm_str_mapping { char * name; uint32_t oxm_id; From ffd01b0276e2652dd6ab35249593496529bf2635 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Wed, 25 Jul 2018 02:05:11 -0300 Subject: [PATCH 168/191] Printing metadata always in hexadecimal. --- udatapath/pipeline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index ad6ea765..c0fa995d 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -631,7 +631,7 @@ execute_entry(struct pipeline *pl, struct flow_entry *entry, hmap_node, hash_int(OXM_OF_METADATA,0), &(*pkt)->handle_std->match.match_fields){ uint64_t *metadata = (uint64_t*) f->value; *metadata = (*metadata & ~wi->metadata_mask) | (wi->metadata & wi->metadata_mask); - VLOG_DBG_RL(LOG_MODULE, &rl, "Executing write metadata: %"PRIu64"", *metadata); + VLOG_DBG_RL(LOG_MODULE, &rl, "Executing write metadata: 0x%"PRIx64"", *metadata); } break; } From 6f02078558bdbadff7c48424dcde87b51a10afc2 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Wed, 25 Jul 2018 02:25:00 -0300 Subject: [PATCH 169/191] New parse64 for parsing tunnel id in set-field action. --- utilities/dpctl.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 71418bf6..2c26d2e8 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -187,6 +187,9 @@ parse32(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32 static int parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint32_t *val, uint32_t **mask); +static int +parse64(char *str, uint64_t max, uint64_t *val); + static int parse64m(char *str, uint64_t max, uint64_t *val, uint64_t **mask); @@ -1915,8 +1918,8 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { /* Tunnel ID */ if (strncmp(token, MATCH_TUNNEL_ID KEY_VAL2, strlen(MATCH_TUNNEL_ID KEY_VAL2)) == 0) { uint64_t *tunn_id = malloc(sizeof(uint64_t)); - if (sscanf(token, MATCH_TUNNEL_ID KEY_VAL2 "0x%"SCNx64"", (tunn_id)) != 1) { - ofp_fatal(0, "Error parsing %s: %s.", MATCH_TUNNEL_ID, token); + if (parse64(token + strlen(MATCH_TUNNEL_ID KEY_VAL2), 0xffffffffffffffffULL, tunn_id)) { + ofp_fatal(0, "Error parsing tunn_id: %s.", token); } else { act->field = (struct ofl_match_tlv*) malloc(sizeof(struct ofl_match_tlv)); @@ -2802,6 +2805,22 @@ parse32m(char *str, struct names32 *names, size_t names_num, uint32_t max, uint3 return 0; } +static int +parse64(char *str, uint64_t max, uint64_t *val) { + int read; + + /* Checks for value in hexadecimal. */ + if (str[0] == '0' && str[1] == 'x') { + read = sscanf(str, "0x%"SCNx64"", val); + } else { + read = sscanf(str, "%"SCNu64"", val); + } + if ((read == 0) || (max == 0) || (*val > max)) { + return -1; + } + return 0; +} + static int parse64m(char *str, uint64_t max, uint64_t *val, uint64_t **mask) { int read; From 62bee870a79d4aff8d7b6fc7b4eae75039302f6a Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Wed, 25 Jul 2018 10:48:19 -0300 Subject: [PATCH 170/191] Fix other memory leak errors when using functions that parses masks. --- utilities/dpctl.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 2c26d2e8..c8a1dc41 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -1530,6 +1530,7 @@ parse_match(char *str, struct ofl_match_header **match) { else { ofl_structs_match_put_eth(m,OXM_OF_IPV6_ND_SLL, eth_src); } + if (mask != NULL) free(mask); continue; } if (strncmp(token, MATCH_IPV6_ND_TLL KEY_VAL, strlen(MATCH_IPV6_ND_TLL KEY_VAL)) == 0) { @@ -1541,6 +1542,7 @@ parse_match(char *str, struct ofl_match_header **match) { else { ofl_structs_match_put_eth(m, OXM_OF_IPV6_ND_TLL,eth_dst); } + if (mask != NULL) free(mask); continue; } @@ -1614,6 +1616,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ETH_SRC; act->field->value = (uint8_t*) dl_src; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_DL_DST KEY_VAL2, strlen(MATCH_DL_DST KEY_VAL2)) == 0) { @@ -1626,6 +1629,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ETH_DST; act->field->value = (uint8_t*) dl_dst; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_DL_TYPE KEY_VAL2, strlen(MATCH_DL_TYPE KEY_VAL2)) == 0) { @@ -1653,6 +1657,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ARP_SHA; act->field->value = (uint8_t*) arp_sha; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_ARP_THA KEY_VAL2, strlen(MATCH_ARP_THA KEY_VAL2)) == 0) { @@ -1666,6 +1671,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ARP_THA; act->field->value = (uint8_t*) arp_tha; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_ARP_SPA KEY_VAL2, strlen(MATCH_ARP_SPA KEY_VAL2)) == 0) { @@ -1679,6 +1685,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ARP_SPA; act->field->value = (uint8_t*) arp_src; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_ARP_TPA KEY_VAL2, strlen(MATCH_ARP_TPA KEY_VAL2)) == 0) { @@ -1692,6 +1699,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_ARP_TPA; act->field->value = (uint8_t*) arp_target; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_ARP_OP KEY_VAL2, strlen(MATCH_ARP_OP KEY_VAL2)) == 0) { @@ -1802,6 +1810,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_IPV4_SRC; act->field->value = (uint8_t*) nw_src; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_NW_DST KEY_VAL2, strlen(MATCH_NW_DST KEY_VAL2)) == 0) { @@ -1816,6 +1825,7 @@ parse_set_field(char *token, struct ofl_action_set_field *act) { act->field->header = OXM_OF_IPV4_DST; act->field->value = (uint8_t*) nw_dst; } + if (mask != NULL) free(mask); return 0; } if (strncmp(token, MATCH_IP_ECN KEY_VAL2, strlen(MATCH_NW_DST KEY_VAL2)) == 0) { @@ -2481,6 +2491,7 @@ parse_port_mod(char *str, struct ofl_msg_port_mod *msg) { if (parse_dl_addr(token + strlen(PORT_MOD_HW_ADDR KEY_VAL), msg->hw_addr, &mask)) { ofp_fatal(0, "Error parsing port_mod hw_addr: %s.", token); } + if (mask != NULL) free(mask); continue; } if (strncmp(token, PORT_MOD_HW_CONFIG KEY_VAL, strlen(PORT_MOD_HW_CONFIG KEY_VAL)) == 0) { From 59ffc49ebd792c0ffdd535ff286f3c1a0b840fac Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Wed, 25 Jul 2018 11:09:13 -0300 Subject: [PATCH 171/191] Change the write metadata instruction mask separator from , to / --- utilities/dpctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index c8a1dc41..379f0342 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -2121,11 +2121,11 @@ parse_inst(char *str, struct ofl_instruction_header **inst) { char *token, *saveptr = NULL; struct ofl_instruction_write_metadata *i = xmalloc(sizeof(struct ofl_instruction_write_metadata)); i->header.type = OFPIT_WRITE_METADATA; - token = strtok_r(s, KEY_SEP, &saveptr); + token = strtok_r(s, MASK_SEP, &saveptr); if (sscanf(token, "0x%"SCNx64"", &(i->metadata)) != 1) { ofp_fatal(0, "Error parsing metadata in write metadata instruction: %s.", s); } - token = strtok_r(NULL, KEY_SEP, &saveptr); + token = strtok_r(NULL, MASK_SEP, &saveptr); if (token == NULL) { i->metadata_mask = 0xffffffffffffffffULL; } else { From 33ab0aeffabbc47cca49a53ddc22042ae5896d95 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Wed, 25 Jul 2018 11:28:52 -0300 Subject: [PATCH 172/191] Using parse64m for write metadata instruction. This allows using both decimal and hexadecimal values for metadata and mask. --- utilities/dpctl.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 379f0342..55344cb6 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -2118,19 +2118,17 @@ parse_inst(char *str, struct ofl_instruction_header **inst) { return; } case (OFPIT_WRITE_METADATA): { - char *token, *saveptr = NULL; + uint64_t *mask; struct ofl_instruction_write_metadata *i = xmalloc(sizeof(struct ofl_instruction_write_metadata)); i->header.type = OFPIT_WRITE_METADATA; - token = strtok_r(s, MASK_SEP, &saveptr); - if (sscanf(token, "0x%"SCNx64"", &(i->metadata)) != 1) { + if (parse64m(s, 0xffffffffffffffffULL, &(i->metadata), &mask)) { ofp_fatal(0, "Error parsing metadata in write metadata instruction: %s.", s); - } - token = strtok_r(NULL, MASK_SEP, &saveptr); - if (token == NULL) { - i->metadata_mask = 0xffffffffffffffffULL; } else { - if (sscanf(token, "0x%"SCNx64"", &(i->metadata_mask)) != 1) { - ofp_fatal(0, "Error parsing metadata_mask in write metadata instruction: %s.", s); + if (mask == NULL) { + i->metadata_mask = 0xffffffffffffffffULL; + } else { + i->metadata_mask = *mask; + free (mask); } } (*inst) = (struct ofl_instruction_header *)i; From bece41a59de7bfdbdc2131909bd2df7ba2b1d7ef Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Wed, 25 Jul 2018 13:15:47 -0300 Subject: [PATCH 173/191] Fix gcc 7.3 warning for -Wliteral-suffix This commit fixes the warning: invalid suffix on literal; C++11 requires a space between literal and string macro [-Wliteral-suffix] when compile the switch using gcc 7.3 on Ubuntu 18.04. --- lib/packets.h | 4 ++-- nbee_link/nbee_link.cpp | 2 +- oflib/ofl-actions-print.c | 2 +- oflib/ofl-structs-print.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/packets.h b/lib/packets.h index c79528f5..8e166ea1 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -104,7 +104,7 @@ static inline bool eth_addr_is_reserved(const uint8_t ea[ETH_ADDR_LEN]) } #define ETH_ADDR_FMT \ - "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 + "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 #define ETH_ADDR_ARGS(ea) \ (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] @@ -198,7 +198,7 @@ BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header)); * argument of a comma expression, but it makes sure that 'ip' is a pointer. * This is useful since a common mistake is to pass an integer instead of a * pointer to IP_ARGS. */ -#define IP_FMT "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8 +#define IP_FMT "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 #define IP_ARGS(ip) \ ((void) (ip)[0], ((uint8_t *) ip)[0]), \ ((uint8_t *) ip)[1], \ diff --git a/nbee_link/nbee_link.cpp b/nbee_link/nbee_link.cpp index 33916abf..98b1d368 100644 --- a/nbee_link/nbee_link.cpp +++ b/nbee_link/nbee_link.cpp @@ -53,7 +53,7 @@ extern "C" int nblink_initialize(void) int NetPDLDecoderFlags = nbDECODER_GENERATEPDML; int ShowNetworkNames = 0; - char* NetPDLFileName = (char*) NETPDLDIR"/"NETPDLFILE; + char* NetPDLFileName = (char*) NETPDLDIR "/" NETPDLFILE; struct stat netpdlstat; struct sigaction sa; diff --git a/oflib/ofl-actions-print.c b/oflib/ofl-actions-print.c index 7f8fa4a2..1bfc4d0d 100644 --- a/oflib/ofl-actions-print.c +++ b/oflib/ofl-actions-print.c @@ -45,7 +45,7 @@ #define ETH_ADDR_FMT \ - "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 + "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 #define ETH_ADDR_ARGS(ea) \ (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] diff --git a/oflib/ofl-structs-print.c b/oflib/ofl-structs-print.c index 71ef0984..776bb44b 100644 --- a/oflib/ofl-structs-print.c +++ b/oflib/ofl-structs-print.c @@ -48,11 +48,11 @@ #define ETH_ADDR_FMT \ - "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8 + "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 #define ETH_ADDR_ARGS(ea) \ (ea)[0], (ea)[1], (ea)[2], (ea)[3], (ea)[4], (ea)[5] -#define IP_FMT "%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8 +#define IP_FMT "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 char * ofl_structs_port_to_string(struct ofl_port *port) { From 7075dec54d877b497de50b78d230ffee6c14474d Mon Sep 17 00:00:00 2001 From: ederlf Date: Thu, 16 Aug 2018 09:58:56 +0000 Subject: [PATCH 174/191] Avoid error when trying to clean a non configured queue. This problem was pointed by @nikchez01 some time ago. This commit handles the specific error message when trying to remove a queue that was not configured. --- lib/netdev.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/netdev.c b/lib/netdev.c index 3c40e8b9..9b5a7ca2 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -223,6 +223,7 @@ get_ipv6_address(const char *name, struct in6_addr *in6) fclose(file); } +#define TC_QDISC_NO_CONFIG_ERR 512 /* All queues in a port, lie beneath a qdisc */ #define TC_QDISC 0x0001 /* This is a root class. In order to efficiently share excess bandwidth @@ -439,7 +440,8 @@ do_setup_qdisc(const char *netdev_name) error = system(command); if (error) { VLOG_WARN(LOG_MODULE, "Problem configuring qdisc for device %s",netdev_name); - return error; + fprintf(stderr, "Error is %d\n", error); + return error; } return 0; } @@ -454,8 +456,8 @@ do_remove_qdisc(const char *netdev_name) int error; snprintf(command, sizeof(command), COMMAND_DEL_DEV_QDISC, netdev_name); error = system(command); - if (error) { - VLOG_WARN(LOG_MODULE, "Problem configuring qdisc for device %s",netdev_name); + if (error && error != TC_QDISC_NO_CONFIG_ERR) { + VLOG_WARN(LOG_MODULE, "Problem configuring qdisc for device %s ",netdev_name); return error; } /* There is no need for a device to already be configured. Therefore no From 992783650881096024bffb04b474d264a69877fe Mon Sep 17 00:00:00 2001 From: ederlf Date: Thu, 16 Aug 2018 21:58:38 +0000 Subject: [PATCH 175/191] Removes unecessary buffer deletion. This commit fixes #278. --- udatapath/datapath.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/udatapath/datapath.c b/udatapath/datapath.c index 85f36b61..df45af71 100644 --- a/udatapath/datapath.c +++ b/udatapath/datapath.c @@ -575,8 +575,6 @@ dp_send_message(struct datapath *dp, struct ofl_msg_header *msg, error = send_openflow_buffer(dp, ofpbuf, sender); if (error) { VLOG_WARN_RL(LOG_MODULE, &rl, "There was an error sending the message!"); - /* TODO Zoltan: is delete needed? */ - ofpbuf_delete(ofpbuf); return error; } return 0; From 039a5d99c48573a25387b82eef1e872ddcebbe2c Mon Sep 17 00:00:00 2001 From: ederlf Date: Thu, 16 Aug 2018 22:03:24 +0000 Subject: [PATCH 176/191] Fixes #279. Fixes memory allocation bug reported by @davidmpc. --- utilities/dpctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 1c1fa0c9..289eba6c 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -638,7 +638,7 @@ flow_mod(struct vconn *vconn, int argc, char *argv[]) { it is an instruction or match. If the match is empty, the argv is modified causing errors to instructions parsing*/ - char *cpy = malloc(strlen(argv[1])); + char *cpy = malloc(strlen(argv[1])+1); memcpy(cpy, argv[1], strlen(argv[1])); parse_match(cpy, &(msg.match)); free(cpy); From 3f84e9042eca9feadbd2fa3a98a2bb9ec722ea4b Mon Sep 17 00:00:00 2001 From: ederlf Date: Thu, 16 Aug 2018 22:13:43 +0000 Subject: [PATCH 177/191] Fixes #280 Deletes spurious free of match structure that could cause double free. Bug discovered by @davidmpc. --- udatapath/pipeline.c | 1 - 1 file changed, 1 deletion(-) diff --git a/udatapath/pipeline.c b/udatapath/pipeline.c index c0fa995d..ba4cc551 100644 --- a/udatapath/pipeline.c +++ b/udatapath/pipeline.c @@ -109,7 +109,6 @@ send_packet_to_controller(struct pipeline *pl, struct packet *pkt, uint8_t table ports */ msg.match = (struct ofl_match_header*)m; dp_send_message(pl->dp, (struct ofl_msg_header *)&msg, NULL); - ofl_structs_free_match((struct ofl_match_header* ) m, NULL); } /* Pass the packet through the flow tables. From 85d9fac44f738eec9b3b77cf3e1cab27a7ccec5c Mon Sep 17 00:00:00 2001 From: ederlf Date: Fri, 17 Aug 2018 20:15:18 +0000 Subject: [PATCH 178/191] Ignore the elements of a Hello message. It fixes the connection with controllers that send the hello elements. It needs to be handled properly, though. --- lib/vconn.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/vconn.c b/lib/vconn.c index 5468307c..607a814a 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -342,13 +342,9 @@ vcs_recv_hello(struct vconn *vconn) struct ofp_header *oh = b->data; if (oh->type == OFPT_HELLO) { - if (b->size > sizeof *oh) { - struct ds msg = DS_EMPTY_INITIALIZER; - ds_put_format(&msg, "%s: extra-long hello:\n", vconn->name); - ds_put_hex_dump(&msg, b->data, b->size, 0, true); - VLOG_WARN_RL(LOG_MODULE, &rl, "%s", ds_cstr(&msg)); - ds_destroy(&msg); - } + /*TODO: handle OFPHET_VERSIONBITMAP */ + /*if (b->size > sizeof *oh) { + }*/ vconn->version = MIN(OFP_VERSION, oh->version); if (vconn->version < vconn->min_version) { From c831d34a127ae0b77a6f9bf6d5ec20ff7117d69d Mon Sep 17 00:00:00 2001 From: ederlf Date: Sat, 18 Aug 2018 13:50:28 +0000 Subject: [PATCH 179/191] Fix for unpacking multiples queues. This commit fixes #104. --- oflib/ofl-messages-unpack.c | 8 +------- oflib/ofl-structs-pack.c | 6 +----- oflib/ofl-structs-unpack.c | 6 +++--- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index bd9a7397..5d4b7ec5 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -1564,7 +1564,6 @@ ofl_msg_unpack_queue_get_config_reply(struct ofp_header *src, size_t *len, struc struct ofp_packet_queue *queue; ofl_err error; size_t i; - size_t len1=0,len2=0; if (*len < sizeof(struct ofp_queue_get_config_reply)) { OFL_LOG_WARN(LOG_MODULE, "Received GET_CONFIG_REPLY has invalid length (%zu).", *len); @@ -1586,18 +1585,13 @@ ofl_msg_unpack_queue_get_config_reply(struct ofp_header *src, size_t *len, struc queue = sr->queues; for (i = 0; i < dr->queues_num; i++) { - /* This is so that it can parse packet with more than 1 queue. - * Previously, dpctl was showing only 1 queue even if more than 1 queues are configured. */ - len1=*len-(sizeof(struct ofp_packet_queue)+sizeof(struct ofp_queue_prop_min_rate))*((int)dr->queues_num-1-i); - len2=*len-(sizeof(struct ofp_packet_queue)+sizeof(struct ofp_queue_prop_min_rate))*((int)dr->queues_num-1-i); - error = ofl_structs_packet_queue_unpack(queue, len, &(dr->queues[i])); + error = ofl_structs_packet_queue_unpack(queue, len, &(dr->queues[i])); if (error) { OFL_UTILS_FREE_ARR_FUN(dr->queues, i, ofl_structs_free_packet_queue); free (dr); return error; } - *len-=len2-len1; //This is so that it can parse packet with more than 1 queue. queue = (struct ofp_packet_queue *)((uint8_t *)queue + ntohs(queue->len)); } diff --git a/oflib/ofl-structs-pack.c b/oflib/ofl-structs-pack.c index a829f908..1ab892aa 100644 --- a/oflib/ofl-structs-pack.c +++ b/oflib/ofl-structs-pack.c @@ -763,7 +763,6 @@ ofl_structs_queue_prop_pack(struct ofl_queue_prop_header *src, dp->prop_header.len = htons(sizeof(struct ofp_queue_prop_min_rate)); dp->rate = htons(sp->rate); memset(dp->pad, 0x00, 6); - return sizeof(struct ofp_queue_prop_min_rate); } case OFPQT_MAX_RATE:{ @@ -816,13 +815,10 @@ ofl_structs_packet_queue_pack(struct ofl_packet_queue *src, struct ofp_packet_qu total_len = sizeof(struct ofp_packet_queue) + ofl_structs_queue_prop_ofp_total_len(src->properties, src->properties_num); - dst->len = htons(total_len); - memset(dst->pad, 0x00, 2); + memset(dst->pad, 0x00, 6); dst->queue_id = htonl(src->queue_id); - data = (uint8_t *)dst + sizeof(struct ofp_packet_queue); - for (i=0; iproperties_num; i++) { len = ofl_structs_queue_prop_pack(src->properties[i], (struct ofp_queue_prop_header *)data); diff --git a/oflib/ofl-structs-unpack.c b/oflib/ofl-structs-unpack.c index e088a441..6664e321 100644 --- a/oflib/ofl-structs-unpack.c +++ b/oflib/ofl-structs-unpack.c @@ -842,7 +842,7 @@ ofl_structs_packet_queue_unpack(struct ofp_packet_queue *src, size_t *len, struc struct ofp_queue_prop_header *prop; ofl_err error; size_t i; - + size_t prop_len; if (*len < ntohs(src->len)) { OFL_LOG_WARN(LOG_MODULE, "Received packet queue has invalid length (%zu).", *len); return ofl_error(OFPET_BAD_ACTION, OFPBRC_BAD_LEN); @@ -852,7 +852,8 @@ ofl_structs_packet_queue_unpack(struct ofp_packet_queue *src, size_t *len, struc q = (struct ofl_packet_queue *)malloc(sizeof(struct ofl_packet_queue)); q->queue_id = ntohl(src->queue_id); - error = ofl_utils_count_ofp_queue_props((uint8_t *)src->properties, *len, &q->properties_num); + prop_len = ntohs(src->len) - sizeof(struct ofp_packet_queue); + error = ofl_utils_count_ofp_queue_props((uint8_t *)src->properties, prop_len, &q->properties_num); if (error) { free(q); return error; @@ -864,7 +865,6 @@ ofl_structs_packet_queue_unpack(struct ofp_packet_queue *src, size_t *len, struc ofl_structs_queue_prop_unpack(prop, len, &(q->properties[i])); prop = (struct ofp_queue_prop_header *)((uint8_t *)prop + ntohs(prop->len)); } - *dst = q; return 0; } From 84bee071156939d835e9db755dc929e7b6b02c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Sat, 8 Sep 2018 12:55:06 +0100 Subject: [PATCH 180/191] Update README.md --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index dddcff19..a3fd3760 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,15 @@ -# OpenFlow 1.3 Software Switch +# Basic OpenFlow Software Switch (BOFUSS) -This is an [OpenFlow 1.3][ofp13] compatible user-space software switch implementation. The code is based on the [Ericsson TrafficLab 1.1 softswitch -implementation][ericssonsw11], with changes in the forwarding plane to support +This is an [OpenFlow 1.3][ofp13] compatible user-space software switch implementation. The code is based on the [Ericsson TrafficLab 1.1 softswitch implementation][ericssonsw11], with changes in the forwarding plane to support OpenFlow 1.3. -**UPDATE**: A new experimental branch with contributions from the [BEBA EU Project][beba-eu] is available with lots of performance improvements and OpenFlow extensions. If you want to try the code checkout to the BEBA-EU branch. +## [Before posting an issue, please read the FAQ first.](https://github.com/CPqD/ofsoftswitch13/wiki/Frequently-Asked-Questions) - ``` - $ git checkout remotes/origin/BEBA-EU - ``` +**UPDATE**: A new experimental branch with contributions from the [BEBA EU Project][beba-eu] is available with lots of performance improvements and OpenFlow extensions. If you want to try the code checkout to the BEBA-EU branch. -**Important notice:** Despite the fact the switch is still popular for adventurers trying to implement own changes to OpenFlow, support now is on a best-effort base. Currently, there are lots of complaints about performance degradation, broken features and installation problems. Although not confirmed, most of the problems seem to be due to most recent linux versions. As the main contributor of the switch, I would like to keep the project alive and fix all the recurrent issues. However, life moves and new projects come, resulting in no time to work on it. I am still happy to help anyone who comes asking for advice on how to make changes in the code, but I cannot guarantee quick and active replies. - *-Eder* +```bash +$ git checkout remotes/origin/BEBA-EU +``` The following components are available in this package: * `ofdatapath`: the switch implementation @@ -19,6 +17,8 @@ The following components are available in this package: * `oflib`: a library for converting to/from 1.3 wire format * `dpctl`: a tool for configuring the switch from the console + + # Getting Started These instructions have been tested on Ubuntu 16.04. Other distributions or versions may need different steps. From 8a900c7a61a7100384cc4c5d5c73d781051e839a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Sat, 8 Sep 2018 13:06:47 +0100 Subject: [PATCH 181/191] Update README.md --- README.md | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index a3fd3760..ecbf0d1e 100644 --- a/README.md +++ b/README.md @@ -111,13 +111,7 @@ You can send requests to the switch using the `dpctl` utility. $ utilities/dpctl tcp:: flow-mod table=0,cmd=add in_port=1 meter:1 ``` -For a complete list of commands and arguments, use the `--help` argument. - -The `dpctl` utility has some limitations at the moment: -* No support for OXM masks -* No support for multipart messages -* Some set_field action fields are not present - +For a complete list of commands and arguments, use the `--help` argument. Also, check the wiki for [Flow Mod examples](https://github.com/CPqD/ofsoftswitch13/wiki/Dpctl-Flow-Mod-Cases) # Contribute Please submit your bug reports, fixes and suggestions as pull requests on @@ -132,26 +126,7 @@ code from the original Stanford switch). This project was supported by Ericsson Innovation Center in Brazil. Formerly maintained by CPqD in technical collaboration with Ericsson Research. -**Contributions:** - -Zoltán Lajos Kis, ofsoftswitch 1.1 implementation and guidance for OpenFlow spec related subjects. - -Jean Tourrilhes, lots of critical memory bug fixes on table features. - -Khai Nguyen Dinh and Thanh Le Dinh, contributions on meter features. - -Rich Lane, added the right compiler linker. - -yu-iwata, fixed flow deletion without matchin out_port. - -Yuval Adler, bug fixes related to matching on vlan and ethertype. - -Hiroyasu OHYAMA, correct URL of NetBee Library. - -... - -*"Your name here" -- please, let us* -*know if we forgot to add your name to the list of contributors!* +[**List of Contributors**](https://github.com/CPqD/ofsoftswitch13/wiki/List-of-Contributors) # Contact E-mail: Eder Leao Fernandes (ederleaofernandes at gmail . com) From 6ed5bf11ca548fec7310da98dd174f992e04d9cb Mon Sep 17 00:00:00 2001 From: abakagamze Date: Mon, 10 Sep 2018 17:10:00 +0300 Subject: [PATCH 182/191] Keep meter high level status after modify ) This commit complies with OpenFlow 1.3.5, keeping the same statistics from the modified meter entry. --- udatapath/meter_table.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/udatapath/meter_table.c b/udatapath/meter_table.c index 61c439ad..10efa2fb 100644 --- a/udatapath/meter_table.c +++ b/udatapath/meter_table.c @@ -163,6 +163,12 @@ meter_table_modify(struct meter_table *table, struct ofl_msg_meter_mod *mod) { list_replace(&new_entry->flow_refs, &entry->flow_refs); list_init(&entry->flow_refs); + new_entry->stats->flow_count = entry->stats->flow_count; + new_entry->stats->packet_in_count = entry->stats->packet_in_count; + new_entry->stats->byte_in_count = entry->stats->byte_in_count; + new_entry->stats->duration_sec = entry->stats->duration_sec; + new_entry->stats->duration_nsec = entry->stats->duration_nsec; + meter_entry_destroy(entry); ofl_msg_free_meter_mod(mod, false); return 0; From d2e515dcc26049c898db135014602a2173927440 Mon Sep 17 00:00:00 2001 From: ederlf Date: Wed, 12 Sep 2018 22:34:32 +0000 Subject: [PATCH 183/191] Increase the size of dpid to 64 bits in ofdatapath cmd --- udatapath/udatapath.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/udatapath/udatapath.c b/udatapath/udatapath.c index ab238aba..5172b198 100644 --- a/udatapath/udatapath.c +++ b/udatapath/udatapath.c @@ -251,10 +251,10 @@ parse_options(struct datapath *dp, int argc, char *argv[]) switch (c) { case 'd': { uint64_t dpid; - if (strlen(optarg) != 12 - || strspn(optarg, "0123456789abcdefABCDEF") != 12) { + if (strlen(optarg) != 16 + || strspn(optarg, "0123456789abcdefABCDEF") != 16) { ofp_fatal(0, "argument to -d or --datapath-id must be " - "exactly 12 hex digits"); + "exactly 16 hex digits"); } dpid = strtoll(optarg, NULL, 16); if (!dpid) { From 0eb7b096419cce00d7ce2b7870c8d4bbf15b9125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Thu, 13 Sep 2018 13:36:16 +0100 Subject: [PATCH 184/191] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ecbf0d1e..d50b182b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ This is an [OpenFlow 1.3][ofp13] compatible user-space software switch implementation. The code is based on the [Ericsson TrafficLab 1.1 softswitch implementation][ericssonsw11], with changes in the forwarding plane to support OpenFlow 1.3. -## [Before posting an issue, please read the FAQ first.](https://github.com/CPqD/ofsoftswitch13/wiki/Frequently-Asked-Questions) +## [Please read the FAQ before posting an issue](https://github.com/CPqD/ofsoftswitch13/wiki/Frequently-Asked-Questions) + +Check the [Wiki](https://github.com/CPqD/ofsoftswitch13/wiki) for some resources that could possibly help you to modify the switch. **UPDATE**: A new experimental branch with contributions from the [BEBA EU Project][beba-eu] is available with lots of performance improvements and OpenFlow extensions. If you want to try the code checkout to the BEBA-EU branch. @@ -18,7 +20,6 @@ The following components are available in this package: * `dpctl`: a tool for configuring the switch from the console - # Getting Started These instructions have been tested on Ubuntu 16.04. Other distributions or versions may need different steps. From de02e95732e0edfe2707d74e2c7c7d800dcabe00 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Mon, 1 Oct 2018 11:17:53 -0300 Subject: [PATCH 185/191] Fix how the switch get valid next table ids for goto in table features. (#286) This commit fix the loop that populates the table features struct with valid goto ids which could be reachable from the current table when using goto instructions. --- udatapath/flow_table.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/udatapath/flow_table.c b/udatapath/flow_table.c index a905dbc9..defa4bad 100644 --- a/udatapath/flow_table.c +++ b/udatapath/flow_table.c @@ -270,7 +270,7 @@ flow_table_timeout(struct flow_table *table) { static void -flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp_table_feature_prop_type type){ +flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp_table_feature_prop_type type, uint8_t table_id){ switch(type){ case OFPTFPT_INSTRUCTIONS: @@ -279,13 +279,13 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp inst_capabilities = xmalloc(sizeof(struct ofl_table_feature_prop_instructions)); inst_capabilities->header.type = type; inst_capabilities->instruction_ids = xmalloc(sizeof(instructions)); - if (PIPELINE_TABLES > 1) { - inst_capabilities->ids_num = N_INSTRUCTIONS; - memcpy(inst_capabilities->instruction_ids, instructions, sizeof(instructions)); - } else { - inst_capabilities->ids_num = N_INSTRUCTIONS - 1; - memcpy(inst_capabilities->instruction_ids, instructions_nogoto, sizeof(instructions_nogoto)); - } + if (table_id < PIPELINE_TABLES - 1) { + inst_capabilities->ids_num = N_INSTRUCTIONS; + memcpy(inst_capabilities->instruction_ids, instructions, sizeof(instructions)); + } else { + inst_capabilities->ids_num = N_INSTRUCTIONS - 1; + memcpy(inst_capabilities->instruction_ids, instructions_nogoto, sizeof(instructions_nogoto)); + } inst_capabilities->header.length = ofl_structs_table_features_properties_ofp_len(&inst_capabilities->header, NULL); (*prop) = (struct ofl_table_feature_prop_header*) inst_capabilities; break; @@ -294,12 +294,15 @@ flow_table_create_property(struct ofl_table_feature_prop_header **prop, enum ofp case OFPTFPT_NEXT_TABLES_MISS:{ struct ofl_table_feature_prop_next_tables *tbl_reachable; int i; + uint8_t next; tbl_reachable = xmalloc(sizeof(struct ofl_table_feature_prop_next_tables)); tbl_reachable->header.type = type; - tbl_reachable->table_num = PIPELINE_TABLES ; - tbl_reachable->next_table_ids = xmalloc(sizeof(uint8_t) * tbl_reachable->table_num); - for(i=0; i < tbl_reachable->table_num; i++) - tbl_reachable->next_table_ids[i] = i; + tbl_reachable->table_num = PIPELINE_TABLES - 1 - table_id; + if (tbl_reachable->table_num > 0) { + tbl_reachable->next_table_ids = xmalloc(sizeof(uint8_t) * tbl_reachable->table_num); + for (i = 0, next = table_id + 1; i < tbl_reachable->table_num; i++, next++) + tbl_reachable->next_table_ids[i] = next; + } tbl_reachable->header.length = ofl_structs_table_features_properties_ofp_len(&tbl_reachable->header, NULL); *prop = (struct ofl_table_feature_prop_header*) tbl_reachable; break; @@ -359,7 +362,7 @@ flow_table_features(struct ofl_table_features *features){ j = 0; for(type = OFPTFPT_INSTRUCTIONS; type <= OFPTFPT_APPLY_SETFIELD_MISS; type++){ //features->properties[j] = xmalloc(sizeof(struct ofl_table_feature_prop_header)); - flow_table_create_property(&features->properties[j], type); + flow_table_create_property(&features->properties[j], type, features->table_id); if(type == OFPTFPT_MATCH|| type == OFPTFPT_WILDCARDS){ type++; } From db04f6107cfdbe5bff338354689e1e09a33bdfd2 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Mon, 1 Oct 2018 11:18:09 -0300 Subject: [PATCH 186/191] Fix compilation warnings for gcc -O0 flag. (#287) This commit fixes some errors when configuring and compiling the switch without gcc optmization flags (./configure CFLAGS='-g -O2' CXXFLAGS='-g -O2'). --- lib/netdev.c | 2 +- oflib/ofl-actions-unpack.c | 2 +- oflib/ofl-messages-unpack.c | 8 ++++---- oflib/ofl-structs-unpack.c | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/netdev.c b/lib/netdev.c index 9b5a7ca2..480641c1 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -1071,7 +1071,7 @@ netdev_recv(struct netdev *netdev, struct ofpbuf *buffer, size_t max_mtu) } /* VLAN tag found. Shift MAC addresses down and insert VLAN tag */ /* Create headroom for the VLAN tag */ - eth_type = ntohs(*((uint16_t *)(buffer->data + ETHER_ADDR_LEN * 2))); + eth_type = ntohs(*((uint16_t *)((uint8_t*)buffer->data + ETHER_ADDR_LEN * 2))); ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN); memmove(buffer->data, (uint8_t*)buffer->data+VLAN_HEADER_LEN, ETH_ALEN * 2); tag = (struct vlan_tag *)((uint8_t*)buffer->data + ETH_ALEN * 2); diff --git a/oflib/ofl-actions-unpack.c b/oflib/ofl-actions-unpack.c index 6954b29e..90c2eb04 100644 --- a/oflib/ofl-actions-unpack.c +++ b/oflib/ofl-actions-unpack.c @@ -346,7 +346,7 @@ ofl_actions_unpack(struct ofp_action_header *src, size_t *len, struct ofl_action return ofl_error(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE); } } - (*dst)->type = (enum ofp_action_type)ntohs(src->type); + (*dst)->type = (enum ofp_action_type)((int)ntohs(src->type)); return 0; } diff --git a/oflib/ofl-messages-unpack.c b/oflib/ofl-messages-unpack.c index 5d4b7ec5..7ef7bb58 100644 --- a/oflib/ofl-messages-unpack.c +++ b/oflib/ofl-messages-unpack.c @@ -66,7 +66,7 @@ ofl_msg_unpack_error(struct ofp_header *src, size_t *len, struct ofl_msg_header de = (struct ofl_msg_error *)malloc(sizeof(struct ofl_msg_error)); - de->type = (enum ofp_error_type)ntohs(se->type); + de->type = (enum ofp_error_type)((int)ntohs(se->type)); de->code = ntohs(se->code); de->data_length = *len; de->data = *len > 0 ? (uint8_t *)memcpy(malloc(*len), se->data, *len) : NULL; @@ -539,7 +539,7 @@ ofl_msg_unpack_group_mod(struct ofp_header *src, size_t *len, struct ofl_msg_hea dm = (struct ofl_msg_group_mod *)malloc(sizeof(struct ofl_msg_group_mod)); - dm->command = (enum ofp_group_mod_command)ntohs(sm->command); + dm->command = (enum ofp_group_mod_command)((int)ntohs(sm->command)); dm->type = sm->type; dm->group_id = ntohl(sm->group_id); @@ -983,7 +983,7 @@ ofl_msg_unpack_multipart_request(struct ofp_header *src,uint8_t *buf, size_t *le } ofls = (struct ofl_msg_multipart_request_header *)(*msg); - ofls->type = (enum ofp_multipart_types)ntohs(os->type); + ofls->type = (enum ofp_multipart_types)((int)ntohs(os->type)); ofls->flags = ntohs(os->flags); return 0; @@ -1523,7 +1523,7 @@ ofl_msg_unpack_multipart_reply(struct ofp_header *src, uint8_t *buf, size_t *len } ofls = (struct ofl_msg_multipart_reply_header *)(*msg); - ofls->type = (enum ofp_multipart_types)ntohs(os->type); + ofls->type = (enum ofp_multipart_types)((int)ntohs(os->type)); ofls->flags = ntohs(os->flags); return 0; diff --git a/oflib/ofl-structs-unpack.c b/oflib/ofl-structs-unpack.c index 6664e321..69462db2 100644 --- a/oflib/ofl-structs-unpack.c +++ b/oflib/ofl-structs-unpack.c @@ -157,7 +157,7 @@ ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct } inst = (struct ofl_instruction_header *)malloc(sizeof(struct ofl_instruction_header)); - inst->type = (enum ofp_instruction_type)ntohs(src->type); + inst->type = (enum ofp_instruction_type)((int)ntohs(src->type)); ilen -= sizeof(struct ofp_instruction_actions); break; @@ -198,7 +198,7 @@ ofl_structs_instructions_unpack(struct ofp_instruction *src, size_t *len, struct } // must set type before check, so free works correctly - inst->type = (enum ofp_instruction_type)ntohs(src->type); + inst->type = (enum ofp_instruction_type)((int)ntohs(src->type)); if (ilen != 0) { *len = *len - ntohs(src->len) + ilen; @@ -346,7 +346,7 @@ ofl_structs_table_properties_unpack(struct ofp_table_feature_prop_header * src, } // must set type before check, so free works correctly - prop->type = (enum ofp_table_feature_prop_type) ntohs(src->type); + prop->type = (enum ofp_table_feature_prop_type)((int)ntohs(src->type)); /* Make sure it can be reused for packing. Jean II */ prop->length = ntohs(src->length); @@ -831,7 +831,7 @@ ofl_structs_queue_prop_unpack(struct ofp_queue_prop_header *src, size_t *len, st } } - (*dst)->type = (enum ofp_queue_properties)ntohs(src->property); + (*dst)->type = (enum ofp_queue_properties)((int)ntohs(src->property)); return 0; } From 367d4d95fce9056ce018990946863771da57ca30 Mon Sep 17 00:00:00 2001 From: ederlf Date: Wed, 10 Oct 2018 08:28:08 +0000 Subject: [PATCH 187/191] Return the number of dpid characters to 12 Because it was breaking compatibility with Mininet. --- udatapath/udatapath.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/udatapath/udatapath.c b/udatapath/udatapath.c index 5172b198..30577b10 100644 --- a/udatapath/udatapath.c +++ b/udatapath/udatapath.c @@ -251,12 +251,12 @@ parse_options(struct datapath *dp, int argc, char *argv[]) switch (c) { case 'd': { uint64_t dpid; - if (strlen(optarg) != 16 - || strspn(optarg, "0123456789abcdefABCDEF") != 16) { + if (strlen(optarg) != 12 + || strspn(optarg, "0123456789abcdefABCDEF") != 12) { ofp_fatal(0, "argument to -d or --datapath-id must be " "exactly 16 hex digits"); } - dpid = strtoll(optarg, NULL, 16); + dpid = strtoll(optarg, NULL, 12); if (!dpid) { ofp_fatal(0, "argument to -d or --datapath-id must " "be nonzero"); From 0910e04d20c2bef9c1c4983d1e6119c71fd50f31 Mon Sep 17 00:00:00 2001 From: Luciano J Chaves Date: Sun, 21 Oct 2018 06:19:57 -0300 Subject: [PATCH 188/191] Fix wrong flow-mod parser for strings with only match or instructions. (#290) When parsing these flow-mod strings (argc == 2), the memcpy is being used to copy the string. However, the memcpy was configured with a wrong number of bytes to copy, skipping the last null string char. This was leading to random error depending on the memory garbage content. --- utilities/dpctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utilities/dpctl.c b/utilities/dpctl.c index 289eba6c..930f9a22 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -639,7 +639,7 @@ flow_mod(struct vconn *vconn, int argc, char *argv[]) { If the match is empty, the argv is modified causing errors to instructions parsing*/ char *cpy = malloc(strlen(argv[1])+1); - memcpy(cpy, argv[1], strlen(argv[1])); + memcpy(cpy, argv[1], strlen(argv[1]) + 1); parse_match(cpy, &(msg.match)); free(cpy); if(msg.match->length <= 4){ From 1939c260226f24c3a09a949ccfe408270ae41042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Fri, 25 Jan 2019 22:09:00 +0000 Subject: [PATCH 189/191] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d50b182b..7f2d4852 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ This is an [OpenFlow 1.3][ofp13] compatible user-space software switch implementation. The code is based on the [Ericsson TrafficLab 1.1 softswitch implementation][ericssonsw11], with changes in the forwarding plane to support OpenFlow 1.3. +## [A paper that describes the basic architecture, selected use cases and a few benchmarks is now available](https://arxiv.org/abs/1901.06699) + ## [Please read the FAQ before posting an issue](https://github.com/CPqD/ofsoftswitch13/wiki/Frequently-Asked-Questions) Check the [Wiki](https://github.com/CPqD/ofsoftswitch13/wiki) for some resources that could possibly help you to modify the switch. From e7050354bb18307806347b77e0ddacc4c7055fa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Fri, 25 Jan 2019 22:13:49 +0000 Subject: [PATCH 190/191] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f2d4852..ea6d283c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ This is an [OpenFlow 1.3][ofp13] compatible user-space software switch implementation. The code is based on the [Ericsson TrafficLab 1.1 softswitch implementation][ericssonsw11], with changes in the forwarding plane to support OpenFlow 1.3. -## [A paper that describes the basic architecture, selected use cases and a few benchmarks is now available](https://arxiv.org/abs/1901.06699) +### [A paper that describes the basic architecture, selected use cases and a few benchmarks is available on Arxiv](https://arxiv.org/abs/1901.06699). +If you use the switch for academic purpuses, please consider refering to it. ## [Please read the FAQ before posting an issue](https://github.com/CPqD/ofsoftswitch13/wiki/Frequently-Asked-Questions) From aaebdbce3dae0f3d9af62f059e3ec5a2813469c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eder=20Le=C3=A3o=20Fernandes?= Date: Fri, 22 May 2020 10:51:48 +0100 Subject: [PATCH 191/191] Update README.md --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ea6d283c..7c7b44ab 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,19 @@ This is an [OpenFlow 1.3][ofp13] compatible user-space software switch implement OpenFlow 1.3. ### [A paper that describes the basic architecture, selected use cases and a few benchmarks is available on Arxiv](https://arxiv.org/abs/1901.06699). -If you use the switch for academic purpuses, please consider refering to it. +If you use the switch for academic purpuses, please consider the use of this citation. + +``` +@article{fernandes2020road, + title={The road to BOFUSS: The basic OpenFlow userspace software switch}, + author={Fernandes, Eder Le{\~a}o and Rojas, Elisa and Alvarez-Horcajo, Joaquin and Kis, Zolt{\`a}n Lajos and Sanvito, Davide and Bonelli, Nicola and Cascone, Carmelo and Rothenberg, Christian Esteve}, + journal={Journal of Network and Computer Applications}, + pages={102685}, + year={2020}, + publisher={Elsevier} +} + +``` ## [Please read the FAQ before posting an issue](https://github.com/CPqD/ofsoftswitch13/wiki/Frequently-Asked-Questions)