Commit ea8bf6d8 authored by Jan Moskyto Matejka's avatar Jan Moskyto Matejka
Browse files

Flowspec: action formatting

parent 5f507ad4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ CF_DECLS
  uint i;
  u32 i32;
  u64 i64;
  float fl;
  ip_addr a;
  ip4_addr ip4;
  ip6_addr ip6;
+5 −0
Original line number Diff line number Diff line
@@ -25,9 +25,14 @@ m4_define(CF_DEFINES, `m4_divert(-1)')
# Keywords are translated to C initializers
m4_define(CF_handle_kw, `m4_divert(1){ "m4_translit($1,[[A-Z]],[[a-z]])", $1, NULL },
m4_divert(-1)')
m4_define(CF_handle_kw_cs, `m4_divert(1){ "$1", $1, NULL },
m4_divert(-1)')
m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_handle_kw($1)]])')
m4_define(CF_keywd_cs, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)CF_handle_kw_cs($1)]])')
m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks
)DNL')
m4_define(CF_KEYWORDS_CS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd_cs]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks
)DNL')

# CLI commands generate keywords as well
m4_define(CF_CLI, `CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ m4_define(CF_iterate, `m4_define([[CF_iter]], m4_defn([[$1]]))CF_itera($2)')
m4_define(CF_keywd, `m4_ifdef([[CF_tok_$1]],,[[m4_define([[CF_tok_$1]],1)m4_define([[CF_toks]],CF_toks $1)]])')
m4_define(CF_KEYWORDS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks
)DNL')
m4_define(CF_KEYWORDS_CS, `m4_define([[CF_toks]],[[]])CF_iterate([[CF_keywd]], [[$@]])m4_ifelse(CF_toks,,,%token[[]]CF_toks
)DNL')

# Dynamic syntax rules
m4_define(CF_dyn_rules,)
+100 −0
Original line number Diff line number Diff line
@@ -80,6 +80,22 @@ flow_type_str(enum flow_type type, int ipv6)
  return ipv6 ? flow6_type_str[type] : flow4_type_str[type];
}

const char *
flow_action_str(uint action)
{
#define C(c, s) case c: return s
  switch(action) {
    C(FLOW_ACTION_TRAFFIC_BYTERATE, "byterate");
    C(FLOW_ACTION_TRAFFIC_ACTION, "action");
    C(FLOW_ACTION_REDIRECT_AS2, "redirect");
    C(FLOW_ACTION_REDIRECT_AS4, "redirect");
    C(FLOW_ACTION_REDIRECT_IP4, "redirect");
    C(FLOW_ACTION_TRAFFIC_MARKING, "mark");
  }
#undef C
  return NULL;
}

/*
 * 	Length
 */
@@ -1174,3 +1190,87 @@ flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f, const char *sep)
{
  return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow6), 1, sep);
}

/* Action */

u64
flow_action_encode_byterate(u16 asn, float rate)
{
  u32 urate;
  memcpy(&urate, &rate, 4);
  return flow_action_encode(FLOW_ACTION_TRAFFIC_BYTERATE, (((u64) asn) << 32) | ((u64) urate));
}

u64
flow_action_encode_redirect(u64 asn, u64 val)
{
  if (asn < 0x10000)
    return (((u64) FLOW_ACTION_REDIRECT_AS2) << 48) | (asn << 32) | (val & 0xffffffff);
  else
    return (((u64) FLOW_ACTION_REDIRECT_AS4) << 48) | (asn << 16) | (val & 0xffff);
}


/**
 * Flow actions are encoded as BGP Extended Community.
 */
uint
flow_action_format_part(char *buf, uint blen, u64 ec)
{
  int type = (ec >> 48);
  switch (type) {
    case FLOW_ACTION_TRAFFIC_BYTERATE:
      {
	float rate;
	u32 urate = (ec & 0xffffffff);
	memcpy(&rate, &urate, sizeof(rate));
	int asn = (ec >> 32) & 0xffff;

	rate *= 8; /* Convert from byterate to bitrate */
	const char *rs;
	if (rate < 2) {
	  rs = "mbps"; rate *= 1000;
	} else if (rate < 2000) {
	  rs = "bps";
	} else if (rate < 2000000) {
	  rs = "kbps"; rate /= 1000;
	} else if (rate < 2000000000) {
	  rs = "Mbps"; rate /= 1000000;
	} else if (rate < 2000000000000) {
	  rs = "Gbps"; rate /= 1000000000;
	} else {
	  rs = "Tbps"; rate /= 1000000000000;
	}

	return bsnprintf(buf, blen, "rate %.3f %s asn %u;", rate, rs, asn);
      }
    case FLOW_ACTION_TRAFFIC_ACTION:
      {
	int total = 0;
	if (ec & FLOW_ACTION_LAST) {
	  int cnt = bsnprintf(buf, blen, "last;");
	  if (cnt < 0)
	    return -1;
	  ADVANCE(buf, blen, cnt);
	  total += cnt;
	}

	if (ec & FLOW_ACTION_SAMPLE) {
	  int cnt = bsnprintf(buf, blen, "sample;");
	  if (cnt < 0)
	    return -1;
	  ADVANCE(buf, blen, cnt);
	  total += cnt;
	}
	return total;
      }
    case FLOW_ACTION_REDIRECT_AS2:
      return bsnprintf(buf, blen, "rt %d,%d;", ((ec >> 32) & 0xffff), (ec & 0xffffffff));
    case FLOW_ACTION_REDIRECT_AS4:
      return bsnprintf(buf, blen, "rt %d,%d;", ((ec >> 16) & 0xffffffff), (ec & 0xffff));
    case FLOW_ACTION_TRAFFIC_MARKING:
      return bsnprintf(buf, blen, "dscp %d;", (ec & 0x3f));
    default:
      return 0;
  }
}
+27 −0
Original line number Diff line number Diff line
@@ -49,6 +49,33 @@ enum flow_type {

const char *flow_type_str(enum flow_type type, int ipv6);

#define FLOW_ACTION_TRAFFIC_BYTERATE	0x8006
#define FLOW_ACTION_TRAFFIC_ACTION	0x8007
#define FLOW_ACTION_REDIRECT_AS2	0x8008
#define FLOW_ACTION_REDIRECT_IP4	0x8108	/* Not supported yet */
#define FLOW_ACTION_REDIRECT_AS4	0x8208
#define FLOW_ACTION_TRAFFIC_MARKING	0x8009

#define FLOW_ACTION_LAST		0x000000000001ULL
#define FLOW_ACTION_SAMPLE		0x000000000002ULL

const char *flow_action_str(uint action);

static inline u64 flow_action_encode(u16 key, u64 value)
{ return value | (((u64) key) << 48); }
u64 flow_action_encode_byterate(u16 asn, float rate);
static inline u64 flow_action_encode_bitrate(u16 asn, float rate)
{ return flow_action_encode_byterate(asn, rate/8); }
static inline u64 flow_action_encode_sample(void)
{ return flow_action_encode(FLOW_ACTION_TRAFFIC_ACTION, FLOW_ACTION_SAMPLE); }
static inline u64 flow_action_encode_last(void)
{ return flow_action_encode(FLOW_ACTION_TRAFFIC_ACTION, FLOW_ACTION_LAST); }
u64 flow_action_encode_redirect(u64 asn, u64 val);
static inline u64 flow_action_encode_dscp(u64 dscp)
{ return (dscp & 0x3f) | (((u64) FLOW_ACTION_TRAFFIC_MARKING) << 48); }


uint flow_action_format_part(char *buf, uint blen, u64 ec);

/*
 * 	Length
Loading