classify: per-interface rx/tx pcap capture filters
[vpp.git] / docs / gettingstarted / developers / vnet.md
index 532eeea..a5cd9e7 100644 (file)
@@ -54,16 +54,16 @@ units to convert buffer indices to buffer pointers:
      n_left_from = frame->n_vectors;
      from = vlib_frame_vector_args (frame);
 
-     /* 
-      * Convert up to VLIB_FRAME_SIZE indices in "from" to 
+     /*
+      * Convert up to VLIB_FRAME_SIZE indices in "from" to
       * buffer pointers in bufs[]
       */
      vlib_get_buffers (vm, from, bufs, n_left_from);
      b = bufs;
      next = nexts;
 
-     /* 
-      * While we have at least 4 vector elements (pkts) to process.. 
+     /*
+      * While we have at least 4 vector elements (pkts) to process..
       */
      while (n_left_from >= 4)
        {
@@ -76,7 +76,7 @@ units to convert buffer indices to buffer pointers:
             vlib_prefetch_buffer_header (b[7], STORE);
            }
 
-         /* 
+         /*
           * $$$ Process 4x packets right here...
           * set next[0..3] to send the packets where they need to go
           */
@@ -91,12 +91,12 @@ units to convert buffer indices to buffer pointers:
         next += 4;
         n_left_from -= 4;
        }
-     /* 
+     /*
       * Clean up 0...3 remaining packets at the end of the incoming frame
       */
      while (n_left_from > 0)
        {
-         /* 
+         /*
           * $$$ Process one packet right here...
           * set next[0..3] to send the packets where they need to go
           */
@@ -117,7 +117,7 @@ units to convert buffer indices to buffer pointers:
      vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
 
      return frame->n_vectors;
-   }  
+   }
 ```
 
 Given a packet processing task to implement, it pays to scout around
@@ -150,12 +150,11 @@ tcp_get_free_buffer_index(...) for an example.
 The following example shows the **main points**, but is not to be
 blindly cut-'n-pasted.
 
-```c                               
+```c
   u32 bi0;
   vlib_buffer_t *b0;
   ip4_header_t *ip;
   udp_header_t *udp;
-  vlib_buffer_free_list_t *fl;
 
   /* Allocate a buffer */
   if (vlib_buffer_alloc (vm, &bi0, 1) != 1)
@@ -164,13 +163,11 @@ blindly cut-'n-pasted.
   b0 = vlib_get_buffer (vm, bi0);
 
   /* Initialize the buffer */
-  fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
-  vlib_buffer_init_for_free_list (b0, fl);
   VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
 
   /* At this point b0->current_data = 0, b0->current_length = 0 */
 
-  /* 
+  /*
    * Copy data into the buffer. This example ASSUMES that data will fit
    * in a single buffer, and is e.g. an ip4 packet.
    */
@@ -179,7 +176,7 @@ blindly cut-'n-pasted.
        clib_memcpy (b0->data, data, vec_len (data));
        b0->current_length = vec_len (data);
      }
-  else 
+  else
      {
        /* OR, build a udp-ip packet (for example) */
        ip = vlib_buffer_get_current (b0);
@@ -204,7 +201,7 @@ blindly cut-'n-pasted.
            udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
            if (udp->checksum == 0)
              udp->checksum = 0xffff;
-      }  
+      }
       b0->current_length = vec_len (sizeof (*ip) + sizeof (*udp) +
                                    vec_len (udp_data));
 
@@ -217,7 +214,7 @@ blindly cut-'n-pasted.
   /* Use the default FIB index for tx lookup. Set non-zero to use another fib */
   vnet_buffer (b0)->sw_if_index[VLIB_TX] = 0;
 
-```  
+```
 
 If your use-case calls for large packet transmission, use
 vlib_buffer_chain_append_data_with_alloc(...) to create the requisite
@@ -239,8 +236,8 @@ indices, and dispatch the frame using vlib_put_frame_to_node(...).
     for (i = 0; i < vec_len (buffer_indices_to_send); i++)
       to_next[i] = buffer_indices_to_send[i];
 
-    vlib_put_frame_to_node (vm, ip4_lookup_node_index, f); 
-``` 
+    vlib_put_frame_to_node (vm, ip4_lookup_node_index, f);
+```
 
 It is inefficient to allocate and schedule single packet frames.
 That's typical in case you need to send one packet per second, but
@@ -282,7 +279,7 @@ Here's a simple example:
         s = format (s, "My trace data was: %d", t-><whatever>);
 
         return s;
-    } 
+    }
 ```
 
 The trace framework hands the per-node format function the data it
@@ -325,8 +322,16 @@ packet data, and a protocol hint.
 
 The buffer index is an opaque 32-bit cookie which allows consumers of
 these data to easily filter/track single packets as they traverse the
-forwarding graph. Multiple records per packet are normal, and to be
-expected. 
+forwarding graph.
+
+Multiple records per packet are normal, and to be expected. Packets
+will appear multiple times as they traverse the vpp forwarding
+graph. In this way, vpp graph dispatch traces are significantly
+different from regular network packet captures from an end-station.
+This property complicates stateful packet analysis.
+
+Restricting stateful analysis to records from a single vpp graph node
+such as "ethernet-input" seems likely to improve the situation.
 
 As of this writing: major version = 1, minor version = 0. Nstrings
 SHOULD be 4 or 5. Consumers SHOULD be wary values less than 4 or
@@ -352,7 +357,7 @@ Example: VLIB_NODE_PROTO_HINT_IP6 means that the first octet of packet
 data SHOULD be 0x60, and should begin an ipv6 packet header.
 
 Downstream consumers of these data SHOULD pay attention to the
-protocol hint. They MUST tolerate inaccurate hints, which WILL occur
+protocol hint. They MUST tolerate inaccurate hints, which MAY occur
 from time to time.
 
 ### Dispatch Pcap Trace Debug CLI
@@ -373,17 +378,17 @@ To save the pcap trace, e.g. in /tmp/dispatch.pcap:
 
 ```
     pcap dispatch trace off
-```    
+```
 
 ### Wireshark dissection of dispatch pcap traces
 
 It almost goes without saying that we built a companion wireshark
-dissector to display these traces. As of this writing, we're in the
-process of trying to upstream the wireshark dissector.
+dissector to display these traces. As of this writing, we have
+upstreamed the wireshark dissector.
 
-Until various games of "fetch me a rock" involved are finished, please
-see the "How to build a vpp dispatch trace aware Wireshark" page
-for build info, and/or take a look at .../extras/wireshark.
+Since it will be a while before wireshark/master/latest makes it into
+all of the popular Linux distros, please see the "How to build a vpp
+dispatch trace aware Wireshark" page for build info.
 
 Here is a sample packet dissection, with some fields omitted for
 clarity.  The point is that the wireshark dissector accurately
@@ -398,15 +403,15 @@ node in question.
         BufferIndex: 0x00036663
     NodeName: ethernet-input
     VPP Buffer Metadata
-        Metadata: flags: 
+        Metadata: flags:
         Metadata: current_data: 0, current_length: 102
         Metadata: current_config_index: 0, flow_id: 0, next_buffer: 0
         Metadata: error: 0, n_add_refs: 0, buffer_pool_index: 0
         Metadata: trace_index: 0, recycle_count: 0, len_not_first_buf: 0
         Metadata: free_list_index: 0
-        Metadata: 
+        Metadata:
     VPP Buffer Opaque
-        Opaque: raw: 00000007 ffffffff 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
+        Opaque: raw: 00000007 ffffffff 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
         Opaque: sw_if_index[VLIB_RX]: 7, sw_if_index[VLIB_TX]: -1
         Opaque: L2 offset 0, L3 offset 0, L4 offset 0, feature arc index 0
         Opaque: ip.adj_index[VLIB_RX]: 0, ip.adj_index[VLIB_TX]: 0
@@ -435,14 +440,14 @@ node in question.
         Opaque: sctp.connection_index: 0, sctp.sid: 0, sctp.ssn: 0, sctp.tsn: 0, sctp.hdr_offset: 0
         Opaque: sctp.data_offset: 0, sctp.data_len: 0, sctp.subconn_idx: 0, sctp.flags: 0x0
         Opaque: snat.flags: 0x0
-        Opaque: 
+        Opaque:
     VPP Buffer Opaque2
-        Opaque2: raw: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
+        Opaque2: raw: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
         Opaque2: qos.bits: 0, qos.source: 0
         Opaque2: loop_counter: 0
         Opaque2: gbp.flags: 0, gbp.src_epg: 0
         Opaque2: pg_replay_timestamp: 0
-        Opaque2: 
+        Opaque2:
     Ethernet II, Src: 06:d6:01:41:3b:92 (06:d6:01:41:3b:92), Dst: IntelCor_3d:f6    Transmission Control Protocol, Src Port: 22432, Dst Port: 54084, Seq: 1, Ack: 1, Len: 36
         Source Port: 22432
         Destination Port: 54084
@@ -465,3 +470,322 @@ This should be of significant value when developing new vpp graph
 nodes. If new code mispositions b->current_data, it will be completely
 obvious from looking at the dispatch trace in wireshark.
 
+## pcap rx, tx, and drop tracing
+
+vpp also supports rx, tx, and drop packet capture in pcap format,
+through the "pcap trace" debug CLI command.
+
+This command is used to start or stop a packet capture, or show the
+status of packet capture. Each of "pcap trace rx", "pcap trace tx",
+and "pcap trace drop" is implemented.  Supply one or more of "rx",
+"tx", and "drop" to enable multiple simultaneous capture types.
+
+These commands have the following optional parameters:
+
+- <b>rx</b> - trace received packets.
+
+- <b>tx</b> - trace transmitted packets.
+
+- <b>drop</b> - trace dropped packets.
+
+- <b>max _nnnn_</b> - file size, number of packet captures. Once
+  <nnnn> packets have been received, the trace buffer buffer is flushed
+  to the indicated file. Defaults to 1000. Can only be updated if packet
+  capture is off.
+
+- <b>max-bytes-per-pkt _nnnn_</b> - maximum number of bytes to trace
+  on a per-packet basis. Must be >32 and less than 9000. Default value:
+  512.
+
+- <b>filter</b> - Use the pcap rx / tx / drop trace filter, which must
+  be configured. Use <b>classify filter pcap...</b> to configure the
+  filter. The filter will only be executed if the per-interface or
+  any-interface tests fail.
+
+- <b>intfc _interface_ | _any_</b> - Used to specify a given interface,
+  or use '<em>any</em>' to run packet capture on all interfaces.
+  '<em>any</em>' is the default if not provided. Settings from a previous
+  packet capture are preserved, so '<em>any</em>' can be used to reset
+  the interface setting.
+
+- <b>file _filename_</b> - Used to specify the output filename. The
+  file will be placed in the '<em>/tmp</em>' directory.  If _filename_
+  already exists, file will be overwritten. If no filename is
+  provided, '<em>/tmp/rx.pcap or tx.pcap</em>' will be used, depending
+  on capture direction. Can only be updated when pcap capture is off.
+
+- <b>status</b> - Displays the current status and configured
+  attributes associated with a packet capture. If packet capture is in
+  progress, '<em>status</em>' also will return the number of packets
+  currently in the buffer. Any additional attributes entered on
+  command line with a '<em>status</em>' request will be ignored.
+
+- <b>filter</b> - Capture packets which match the current packet
+  trace filter set. See next section. Configure the capture filter
+  first.
+
+## packet trace capture filtering
+
+The "classify filter pcap | <interface-name> " debug CLI command
+constructs an arbitrary set of packet classifier tables for use with
+"pcap rx | tx | drop trace," and with the vpp packet tracer on a
+per-interface basis.
+
+Packets which match a rule in the classifier table chain will be
+traced. The tables are automatically ordered so that matches in the
+most specific table are tried first.
+
+It's reasonably likely that folks will configure a single table with
+one or two matches. As a result, we configure 8 hash buckets and 128K
+of match rule space by default. One can override the defaults by
+specifying "buckets <nnn>" and "memory-size <xxx>" as desired.
+
+To build up complex filter chains, repeatedly issue the classify
+filter debug CLI command. Each command must specify the desired mask
+and match values. If a classifier table with a suitable mask already
+exists, the CLI command adds a match rule to the existing table.  If
+not, the CLI command add a new table and the indicated mask rule
+
+### Configure a simple pcap classify filter
+
+```
+    classify filter pcap mask l3 ip4 src match l3 ip4 src 192.168.1.11
+    pcap trace rx max 100 filter
+```
+
+### Configure a simple per-interface capture filter
+
+```
+    classify filter GigabitEthernet3/0/0 mask l3 ip4 src match l3 ip4 src 192.168.1.11"
+    pcap trace rx max 100 intfc GigabitEthernet3/0/0
+```
+
+Note that per-interface capture filters are _always_ applied.
+
+### Clear per-interface capture filters
+
+```
+    classify filter GigabitEthernet3/0/0 del
+```
+
+### Configure another fairly simple pcap classify filter
+
+```
+   classify filter pcap mask l3 ip4 src dst match l3 ip4 src 192.168.1.10 dst 192.168.2.10
+   pcap trace tx max 100 filter
+```
+
+### Clear all current classifier filters
+
+```
+    classify filter del
+```
+
+### To inspect the classifier tables
+
+```
+   show classify table [verbose]
+```
+
+The verbose form displays all of the match rules, with hit-counters.
+
+### Terse description of the "mask <xxx>" syntax:
+
+```
+    l2 src dst proto tag1 tag2 ignore-tag1 ignore-tag2 cos1 cos2 dot1q dot1ad
+    l3 ip4 <ip4-mask> ip6 <ip6-mask>
+    <ip4-mask> version hdr_length src[/width] dst[/width]
+               tos length fragment_id ttl protocol checksum
+    <ip6-mask> version traffic-class flow-label src dst proto
+               payload_length hop_limit protocol
+    l4 tcp <tcp-mask> udp <udp_mask> src_port dst_port
+    <tcp-mask> src dst  # ports
+    <udp-mask> src_port dst_port
+```
+
+To construct **matches**, add the values to match after the indicated
+keywords in the mask syntax. For example: "... mask l3 ip4 src" ->
+"... match l3 ip4 src 192.168.1.11"
+
+## VPP Packet Generator
+
+We use the VPP packet generator to inject packets into the forwarding
+graph. The packet generator can replay pcap traces, and generate packets
+out of whole cloth at respectably high performance.
+
+The VPP pg enables quite a variety of use-cases, ranging from functional
+testing of new data-plane nodes to regression testing to performance
+tuning.
+
+## PG setup scripts
+
+PG setup scripts describe traffic in detail, and leverage vpp debug
+CLI mechanisms. It's reasonably unusual to construct a pg setup script
+which doesn't include a certain amount of interface and FIB configuration.
+
+For example:
+
+```
+    loop create
+    set int ip address loop0 192.168.1.1/24
+    set int state loop0 up
+
+    packet-generator new {
+        name pg0
+        limit 100
+        rate 1e6
+        size 300-300
+        interface loop0
+        node ethernet-input
+        data { IP4: 1.2.3 -> 4.5.6
+               UDP: 192.168.1.10 - 192.168.1.254 -> 192.168.2.10
+               UDP: 1234 -> 2345
+               incrementing 286
+        }
+    }
+```
+
+A packet generator stream definition includes two major sections:
+- Stream Parameter Setup
+- Packet Data
+
+### Stream Parameter Setup
+
+Given the example above, let's look at how to set up stream
+parameters:
+
+- **name pg0** - Name of the stream, in this case "pg0"
+
+- **limit 1000** - Number of packets to send when the stream is
+enabled. "limit 0" means send packets continuously.
+
+- **maxframe \<nnn\>** - Maximum frame size. Handy for injecting
+multiple frames no larger than \<nnn\>. Useful for checking dual /
+quad loop codes
+
+- **rate 1e6** - Packet injection rate, in this case 1 MPPS. When not
+specified, the packet generator injects packets as fast as possible
+
+- **size 300-300** - Packet size range, in this case send 300-byte packets
+
+- **interface loop0** - Packets appear as if they were received on the
+specified interface. This datum is used in multiple ways: to select
+graph arc feature configuration, to select IP FIBs.  Configure
+features e.g. on loop0 to exercise those features.
+
+- **tx-interface \<name\>** - Packets will be transmitted on the
+indicated interface. Typically required only when injecting packets
+into post-IP-rewrite graph nodes.
+
+- **pcap \<filename\>** - Replay packets from the indicated pcap
+capture file. "make test" makes extensive use of this feature:
+generate packets using scapy, save them in a .pcap file, then inject
+them into the vpp graph via a vpp pg "pcap \<filename\>" stream
+definition
+
+- **worker \<nn\>** - Generate packets for the stream using the
+indicated vpp worker thread. The vpp pg generates and injects O(10
+MPPS / core).  Use multiple stream definitions and worker threads to
+generate and inject enough traffic to easily fill a 40 gbit pipe with
+small packets.
+
+### Data definition
+
+Packet generator data definitions make use of a layered implementation
+strategy. Networking layers are specified in order, and the notation can
+seem a bit counter-intuitive. In the example above, the data
+definition stanza constructs a set of L2-L4 headers layers, and
+uses an incrementing fill pattern to round out the requested 300-byte
+packets.
+
+- **IP4: 1.2.3 -> 4.5.6** - Construct an L2 (MAC) header with the ip4
+ethertype (0x800), src MAC address of 00:01:00:02:00:03 and dst MAC
+address of 00:04:00:05:00:06. Mac addresses may be specified in either
+_xxxx.xxxx.xxxx_ format or _xx:xx:xx:xx:xx:xx_ format.
+
+- **UDP: 192.168.1.10 - 192.168.1.254 -> 192.168.2.10** - Construct an
+incrementing set of L3 (IPv4) headers for successive packets with
+source addresses ranging from .10 to .254. All packets in the stream
+have a constant dest address of 192.168.2.10. Set the protocol field
+to 17, UDP.
+
+- **UDP: 1234 -> 2345** - Set the UDP source and destination ports to
+1234 and 2345, respectively
+
+- **incrementing 256** - Insert up to 256 incrementing data bytes.
+
+Obvious variations involve "s/IP4/IP6/" in the above, along with
+changing from IPv4 to IPv6 address notation.
+
+The vpp pg can set any / all IPv4 header fields, including tos, packet
+length, mf / df / fragment id and offset, ttl, protocol, checksum, and
+src/dst addresses. Take a look at ../src/vnet/ip/ip[46]_pg.c for
+details.
+
+If all else fails, specify the entire packet data in hex:
+
+- **hex 0xabcd...** - copy hex data verbatim into the packet
+
+When replaying pcap files ("**pcap \<filename\>**"), do not specify a
+data stanza.
+
+### Diagnosing "packet-generator new" parse failures
+
+If you want to inject packets into a brand-new graph node, remember
+to tell the packet generator debug CLI how to parse the packet
+data stanza.
+
+If the node expects L2 Ethernet MAC headers, specify ".unformat_buffer
+= unformat_ethernet_header":
+
+```
+    /* *INDENT-OFF* */
+    VLIB_REGISTER_NODE (ethernet_input_node) =
+    {
+      <snip>
+      .unformat_buffer = unformat_ethernet_header,
+      <snip>
+    };
+```
+
+Beyond that, it may be necessary to set breakpoints in
+.../src/vnet/pg/cli.c. Debug image suggested.
+
+When debugging new nodes, it may be far simpler to directly inject
+ethernet frames - and add a corresponding vlib_buffer_advance in the
+new node - than to modify the packet generator.
+
+## Debug CLI
+
+The descriptions above describe the "packet-generator new" debug CLI in
+detail.
+
+Additional debug CLI commands include:
+
+```
+    vpp# packet-generator enable [<stream-name>]
+```
+
+which enables the named stream, or all streams.
+
+```
+    vpp# packet-generator disable [<stream-name>]
+```
+
+disables the named stream, or all streams.
+
+
+```
+    vpp# packet-generator delete <stream-name>
+```
+
+Deletes the named stream.
+
+```
+    vpp# packet-generator configure <stream-name> [limit <nnn>]
+         [rate <f64-pps>] [size <nn>-<nn>]
+```
+
+Changes stream parameters without having to recreate the entire stream
+definition. Note that re-issuing a "packet-generator new" command will
+correctly recreate the named stream.