aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/cop/cop.c
blob: edd09856092deb6d581f3f81466d12e3b4b16b38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
# $Id: mrt.py 29 2007-01-26 02:29:07Z jon.oberheide $

"""Multi-threaded Routing Toolkit."""

import dpkt
import bgp

# Multi-threaded Routing Toolkit
# http://www.ietf.org/internet-drafts/draft-ietf-grow-mrt-03.txt

# MRT Types
NULL			= 0
START			= 1
DIE			= 2
I_AM_DEAD		= 3
PEER_DOWN		= 4
BGP			= 5	# Deprecated by BGP4MP
RIP			= 6
IDRP			= 7
RIPNG			= 8
BGP4PLUS		= 9	# Deprecated by BGP4MP
BGP4PLUS_01		= 10	# Deprecated by BGP4MP
OSPF			= 11
TABLE_DUMP		= 12
BGP4MP			= 16
BGP4MP_ET		= 17
ISIS			= 32
ISIS_ET			= 33
OSPF_ET			= 64

# BGP4MP Subtypes
BGP4MP_STATE_CHANGE	= 0
BGP4MP_MESSAGE		= 1
BGP4MP_ENTRY		= 2
BGP4MP_SNAPSHOT		= 3
BGP4MP_MESSAGE_32BIT_AS	= 4

# Address Family Types
AFI_IPv4		= 1
AFI_IPv6		= 2

class MRTHeader(dpkt.Packet):
    __hdr__ = (
        ('ts', 'I', 0),
        ('type', 'H', 0),
        ('subtype', 'H', 0),
        ('len', 'I', 0)
        )

class TableDump(dpkt.Packet):
    __hdr__ = (
        ('view', 'H', 0),
        ('seq', 'H', 0),
        ('prefix', 'I', 0),
        ('prefix_len', 'B', 0),
        ('status', 'B', 1),
        ('originated_ts', 'I', 0),
        ('peer_ip', 'I', 0),
        ('peer_as', 'H', 0),
        ('attr_len', 'H'
/*
 * Copyright (c) 2016 Cisco and/or its affiliates.
 * 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 <vnet/cop/cop.h>

cop_main_t cop_main;

static clib_error_t *
cop_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add)
{
  cop_main_t * cm = &cop_main;
  cop_config_data_t _data, *data = &_data;
  vlib_main_t * vm = cm->vlib_main;
  vnet_hw_interface_t * hi = vnet_get_sup_hw_interface (vnm, sw_if_index);;
  cop_config_main_t * ccm;
  int address_family;
  u32 ci, default_next;

  clib_memset (data, 0, sizeof(*data));

  /*
   * Ignore local interface, pg interfaces. $$$ need a #define for the
   * first "real" interface. The answer is 5 at the moment.
   */
  if (hi->dev_class_index == vnet_local_interface_device_class.index)
    return 0;

   for (address_family = VNET_COP_IP4; address_family < VNET_N_COPS;
       address_family++)
    {
      ccm = &cm->cop_config_mains[address_family];

      /*
       * Once-only code to initialize the per-address-family
       * cop feature subgraphs.
       * Since the (single) start-node, cop-input, must be able
       * to push pkts into three separate subgraphs, we
       * use a unified cop_feature_type_t enumeration.
       */

      if (!(ccm->config_main.node_index_by_feature_index))
        {
          switch (address_family)
            {
            case VNET_COP_IP4:
              {
                static char * start_nodes[] = { "cop-input" };
                static char * feature_nodes[] = {
                  [IP4_RX_COP_WHITELIST] = "ip4-cop-whitelist",
                  [IP4_RX_COP_INPUT] = "ip4-input",
                };

                vnet_config_init (vm, &ccm->config_main,
                                  start_nodes, ARRAY_LEN(start_nodes),
                                  feature_nodes, ARRAY_LEN(feature_nodes));
              }
              break;
            case VNET_COP_IP6:
              {
                static char * start_nodes[] = { "cop-input" };
                static char * feature_nodes[] = {
                  [IP6_RX_COP_WHITELIST] = "ip6-cop-whitelist",
                  [IP6_RX_COP_INPUT] = "ip6-input",
                };
                vnet_config_init (vm, &ccm->config_main,
                                  start_nodes, ARRAY_LEN(start_nodes),
                                  feature_nodes, ARRAY_LEN(feature_nodes));
              }
              break;

            case VNET_COP_DEFAULT:
              {
                static char * start_nodes[] = { "cop-input" };
                static char * feature_nodes[] = {
                  [DEFAULT_RX_COP_WHITELIST] = "default-cop-whitelist",
                  [DEFAULT_RX_COP_INPUT] = "ethernet-input",
                };
                vnet_config_init (vm, &ccm->config_main,
                                  start_nodes, ARRAY_LEN(start_nodes),
                                  feature_nodes, ARRAY_LEN(feature_nodes));
              }
              break;

            default:
              clib_warning ("bug");
              break;
            }
        }
      vec_validate_init_empty (ccm->config_index_by_sw_if_index, sw_if_index,
                               ~0);

      ci = ccm->config_index_by_sw_if_index[sw_if_index];

      /* Create a sensible initial config: send pkts to xxx-input */
      if (address_family == VNET_COP_IP4)
        default_next = IP4_RX_COP_INPUT;
      else if (address_family == VNET_COP_IP6)
        default_next = IP6_RX_COP_INPUT;
      else
        default_next = DEFAULT_RX_COP_INPUT;

      if (is_add)
        ci = vnet_config_add_feature (vm, &ccm->config_main,
                                      ci,
                                      default_next,
                                      data, sizeof(*data));
      else
        ci = vnet_config_del_feature (vm, &ccm->config_main,
                                      ci,
                                      default_next,
                                      data, sizeof(*data));

      ccm->config_index_by_sw_if_index[sw_if_index] = ci;
    }
  return 0;
}

VNET_SW_INTERFACE_ADD_DEL_FUNCTION (cop_sw_interface_add_del);

static clib_error_t *
cop_init (vlib_main_t *vm)
{
  cop_main_t * cm = &cop_main;

  cm->vlib_main = vm;
  cm->vnet_main = vnet_get_main();

  return 0;
}

/* *INDENT-OFF* */
VLIB_INIT_FUNCTION (cop_init) =
{
  .runs_after = VLIB_INITS ("ip4_whitelist_init", "ip6_whitelist_init"),
};
/* *INDENT-ON* */

int cop_interface_enable_disable (u32 sw_if_index, int enable_disable)
{
  cop_main_t * cm = &cop_main;
  vnet_sw_interface_t * sw;
  int rv;
  u32 node_index = enable_disable ? cop_input_node.index : ~0;

  /* Not a physical port? */
  sw = vnet_get_sw_interface (cm->vnet_main, sw_if_index);
  if (sw->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
    return VNET_API_ERROR_INVALID_SW_IF_INDEX;

  /*
   * Redirect pkts from the driver to the cop node.
   * Returns VNET_API_ERROR_UNIMPLEMENTED if the h/w driver
   * doesn't implement the API.
   *
   * Node_index = ~0 => shut off redirection
   */
  rv = vnet_hw_interface_rx_redirect_to_node (cm->vnet_main, sw_if_index,
                                              node_index);
  return rv;
}

static clib_error_t *
cop_enable_disable_command_fn (vlib_main_t * vm,
                                unformat_input_t * input,
                                vlib_cli_command_t * cmd)
{
  cop_main_t * cm = &cop_main;
  u32 sw_if_index = ~0;
  int enable_disable = 1;

  int rv;

  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
    if (unformat (input, "disable"))
      enable_disable = 0;
    else if (unformat (input, "%U", unformat_vnet_sw_interface,
                       cm->vnet_main, &sw_if_index))
      ;
    else
      break;
  }

  if (sw_if_index == ~0)
    return clib_error_return (0, "Please specify an interface...");

  rv = cop_interface_enable_disable (sw_if_index, enable_disable);

  switch(rv) {
  case 0:
    break;

  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
    return clib_error_return
      (0, "Invalid interface, only works on physical ports");
    break;

  case VNET_API_ERROR_UNIMPLEMENTED:
    return clib_error_return (0, "Device driver doesn't support redirection");
    break;

  default:
    return clib_error_return (0, "cop_interface_enable_disable returned %d",
                              rv);
  }
  return 0;
}

VLIB_CLI_COMMAND (cop_interface_command, static) = {
    .path = "cop interface",
    .short_help =
    "cop interface <interface-name> [disable]",
    .function = cop_enable_disable_command_fn,
};


int cop_whitelist_enable_disable (cop_whitelist_enable_disable_args_t *a)
{
  cop_main_t * cm = &cop_main;
  vlib_main_t * vm = cm->vlib_main;
  ip4_main_t * im4 = &ip4_main;
  ip6_main_t * im6 = &ip6_main;
  int address_family;
  int is_add;
  cop_config_main_t * ccm;
  u32 next_to_add_del = 0;
  uword * p;
  u32 fib_index = 0;
  u32 ci;
  cop_config_data_t _data, *data=&_data;

  /*
   * Enable / disable whitelist processing on the specified interface
   */

  for (address_family = VNET_COP_IP4; address_family < VNET_N_COPS;
       address_family++)
    {
      ccm = &cm->cop_config_mains[address_family];

      switch(address_family)
        {
        case VNET_COP_IP4:
          is_add = (a->ip4 != 0);
          next_to_add_del = IP4_RX_COP_WHITELIST;
          /* configured opaque data must match, or no supper */
          p = hash_get (im4->fib_index_by_table_id, a->fib_id);
          if (p)
            fib_index = p[0];
          else
            {
              if (is_add)
                return VNET_API_ERROR_NO_SUCH_FIB;
              else
                continue;
            }
          break;

        case VNET_COP_IP6:
          is_add = (a->ip6 != 0);
          next_to_add_del = IP6_RX_COP_WHITELIST;
          p = hash_get (im6->fib_index_by_table_id, a->fib_id);
          if (p)
            fib_index = p[0];
          else
            {
              if (is_add)
                return VNET_API_ERROR_NO_SUCH_FIB;
              else
                continue;
            }
          break;

        case VNET_COP_DEFAULT:
          is_add = (a->default_cop != 0);
          next_to_add_del = DEFAULT_RX_COP_WHITELIST;
          break;

        default:
          clib_warning ("BUG");
        }

      ci = ccm->config_index_by_sw_if_index[a->sw_if_index];
      data->fib_index = fib_index;

      if (is_add)
	ci = vnet_config_add_feature (vm, &ccm->config_main,
				      ci,
                                      next_to_add_del,
                                      data, sizeof (*data));
      else
	ci = vnet_config_del_feature (vm, &ccm->config_main,
				      ci,
                                      next_to_add_del,
                                      data, sizeof (*data));

      ccm->config_index_by_sw_if_index[a->sw_if_index] = ci;
    }
  return 0;
}

static clib_error_t *
cop_whitelist_enable_disable_command_fn (vlib_main_t * vm,
                                         unformat_input_t * input,
                                         vlib_cli_command_t * cmd)
{
  cop_main_t * cm = &cop_main;
  u32 sw_if_index = ~0;
  u8 ip4 = 0;
  u8 ip6 = 0;
  u8 default_cop = 0;
  u32 fib_id = 0;
  int rv;
  cop_whitelist_enable_disable_args_t _a, * a = &_a;

  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
    if (unformat (input, "ip4"))
      ip4 = 1;
    else if (unformat (input, "ip6"))
      ip6 = 1;
    else if (unformat (input, "default"))
      default_cop = 1;
    else if (unformat (input, "%U", unformat_vnet_sw_interface,
                       cm->vnet_main, &sw_if_index))
      ;
    else if (unformat (input, "fib-id %d", &fib_id))
      ;
    else
      break;
  }

  if (sw_if_index == ~0)
    return clib_error_return (0, "Please specify an interface...");

  a->sw_if_index = sw_if_index;
  a->ip4 = ip4;
  a->ip6 = ip6;
  a->default_cop = default_cop;
  a->fib_id = fib_id;

  rv = cop_whitelist_enable_disable (a);

  switch(rv) {
  case 0:
    break;

  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
    return clib_error_return
      (0, "Invalid interface, only works on physical ports");
    break;

  case VNET_API_ERROR_NO_SUCH_FIB:
    return clib_error_return
      (0, "Invalid fib");
    break;

  case VNET_API_ERROR_UNIMPLEMENTED:
    return clib_error_return (0, "Device driver doesn't support redirection");
    break;

  default:
    return clib_error_return (0, "cop_whitelist_enable_disable returned %d",
                              rv);
  }

  return 0;
}

VLIB_CLI_COMMAND (cop_whitelist_command, static) = {
    .path = "cop whitelist",
    .short_help =
    "cop whitelist <interface-name> [ip4][ip6][default][fib-id <NN>][disable]",
    .function = cop_whitelist_enable_disable_command_fn,
};