ospfd/ospfclient: add option to flush/withdrawal with zero length

default behavior is unchanged, i.e., to not zero

Signed-off-by: Lou Berger <lberger@labn.net>
This commit is contained in:
Lou Berger 2022-10-16 15:19:37 +00:00
parent 08172828f6
commit 2f30cb2574
10 changed files with 70 additions and 27 deletions

View file

@ -482,7 +482,8 @@ int ospf_apiclient_lsa_originate(struct ospf_apiclient *oclient,
int ospf_apiclient_lsa_delete(struct ospf_apiclient *oclient, int ospf_apiclient_lsa_delete(struct ospf_apiclient *oclient,
struct in_addr addr, uint8_t lsa_type, struct in_addr addr, uint8_t lsa_type,
uint8_t opaque_type, uint32_t opaque_id) uint8_t opaque_type, uint32_t opaque_id,
uint8_t flags)
{ {
struct msg *msg; struct msg *msg;
int rc; int rc;
@ -497,7 +498,7 @@ int ospf_apiclient_lsa_delete(struct ospf_apiclient *oclient,
/* opaque_id is in host byte order and will be converted /* opaque_id is in host byte order and will be converted
* to network byte order by new_msg_delete_request */ * to network byte order by new_msg_delete_request */
msg = new_msg_delete_request(ospf_apiclient_get_seqnr(), addr, lsa_type, msg = new_msg_delete_request(ospf_apiclient_get_seqnr(), addr, lsa_type,
opaque_type, opaque_id); opaque_type, opaque_id, flags);
rc = ospf_apiclient_send_request(oclient, msg); rc = ospf_apiclient_send_request(oclient, msg);
return rc; return rc;

View file

@ -95,7 +95,8 @@ int ospf_apiclient_lsa_originate(struct ospf_apiclient *oclient,
host byte order */ host byte order */
int ospf_apiclient_lsa_delete(struct ospf_apiclient *oclient, int ospf_apiclient_lsa_delete(struct ospf_apiclient *oclient,
struct in_addr addr, uint8_t lsa_type, struct in_addr addr, uint8_t lsa_type,
uint8_t opaque_type, uint32_t opaque_id); uint8_t opaque_type, uint32_t opaque_id,
uint8_t flags);
/* Fetch async message and handle it */ /* Fetch async message and handle it */
int ospf_apiclient_handle_async(struct ospf_apiclient *oclient); int ospf_apiclient_handle_async(struct ospf_apiclient *oclient);

View file

@ -98,9 +98,10 @@ static void lsa_delete(struct thread *t)
printf("Deleting LSA... "); printf("Deleting LSA... ");
rc = ospf_apiclient_lsa_delete(oclient, area_id, rc = ospf_apiclient_lsa_delete(oclient, area_id,
atoi(args[2]), /* lsa type */ atoi(args[2]), /* lsa type */
atoi(args[3]), /* opaque type */ atoi(args[3]), /* opaque type */
atoi(args[4])); /* opaque ID */ atoi(args[4]), /* opaque ID */
0); /* send data in withdrawals */
printf("done, return code is = %d\n", rc); printf("done, return code is = %d\n", rc);
} }

View file

@ -62,13 +62,16 @@ smsg_info = {
MSG_REGISTER_EVENT: ("REGISTER_EVENT", FMT_LSA_FILTER), MSG_REGISTER_EVENT: ("REGISTER_EVENT", FMT_LSA_FILTER),
MSG_SYNC_LSDB: ("SYNC_LSDB", FMT_LSA_FILTER), MSG_SYNC_LSDB: ("SYNC_LSDB", FMT_LSA_FILTER),
MSG_ORIGINATE_REQUEST: ("ORIGINATE_REQUEST", ">II" + FMT_LSA_HEADER[1:]), MSG_ORIGINATE_REQUEST: ("ORIGINATE_REQUEST", ">II" + FMT_LSA_HEADER[1:]),
MSG_DELETE_REQUEST: ("DELETE_REQUEST", ">IBBxxL"), MSG_DELETE_REQUEST: ("DELETE_REQUEST", ">IBBxBL"),
MSG_SYNC_REACHABLE: ("MSG_SYNC_REACHABLE", ""), MSG_SYNC_REACHABLE: ("MSG_SYNC_REACHABLE", ""),
MSG_SYNC_ISM: ("MSG_SYNC_ISM", ""), MSG_SYNC_ISM: ("MSG_SYNC_ISM", ""),
MSG_SYNC_NSM: ("MSG_SYNC_NSM", ""), MSG_SYNC_NSM: ("MSG_SYNC_NSM", ""),
MSG_SYNC_ROUTER_ID: ("MSG_SYNC_ROUTER_ID", ""), MSG_SYNC_ROUTER_ID: ("MSG_SYNC_ROUTER_ID", ""),
} }
# OSPF API MSG Delete Flag.
OSPF_API_DEL_ZERO_LEN_LSA = 0x01 # send withdrawal with no LSA data
# -------------------------- # --------------------------
# Messages from OSPF daemon. # Messages from OSPF daemon.
# -------------------------- # --------------------------
@ -842,7 +845,7 @@ class OspfOpaqueClient(OspfApiClient):
await self._assure_opaque_ready(lsa_type, otype) await self._assure_opaque_ready(lsa_type, otype)
await self.msg_send_raises(mt, msg) await self.msg_send_raises(mt, msg)
async def delete_opaque_data(self, addr, lsa_type, otype, oid): async def delete_opaque_data(self, addr, lsa_type, otype, oid, flags=0):
"""Delete an instance of opaque data. """Delete an instance of opaque data.
Delete an instance of opaque data. This call will register for the given Delete an instance of opaque data. This call will register for the given
@ -854,6 +857,7 @@ class OspfOpaqueClient(OspfApiClient):
otype: (octet) opaque type. Note: the type will be registered if the user otype: (octet) opaque type. Note: the type will be registered if the user
has not explicity done that yet with `register_opaque_data`. has not explicity done that yet with `register_opaque_data`.
oid: (3 octets) ID of this opaque data oid: (3 octets) ID of this opaque data
flags: (octet) optional flags (e.g., OSPF_API_DEL_ZERO_LEN_LSA, defaults to no flags)
Raises: Raises:
See `msg_send_raises` See `msg_send_raises`
""" """
@ -862,7 +866,7 @@ class OspfOpaqueClient(OspfApiClient):
mt = MSG_DELETE_REQUEST mt = MSG_DELETE_REQUEST
await self._assure_opaque_ready(lsa_type, otype) await self._assure_opaque_ready(lsa_type, otype)
mp = struct.pack(msg_fmt[mt], int(addr), lsa_type, otype, oid) mp = struct.pack(msg_fmt[mt], int(addr), lsa_type, otype, flags, oid)
await self.msg_send_raises(mt, mp) await self.msg_send_raises(mt, mp)
async def register_opaque_data(self, lsa_type, otype, callback=None): async def register_opaque_data(self, lsa_type, otype, callback=None):
@ -1115,23 +1119,28 @@ async def async_main(args):
except ValueError: except ValueError:
addr = ip(aval) addr = ip(aval)
oargs = [addr, ltype, int(_s.pop(False)), int(_s.pop(False))] oargs = [addr, ltype, int(_s.pop(False)), int(_s.pop(False))]
assert len(_s) <= 1, "Bad format for action argument"
try:
b = bytes.fromhex(_s.pop(False))
except IndexError:
b = b""
logging.info("opaque data is %s octets", len(b))
# Needs to be multiple of 4 in length
mod = len(b) % 4
if mod:
b += b"\x00" * (4 - mod)
logging.info("opaque padding to %s octets", len(b))
if what.casefold() == "add": if what.casefold() == "add":
try:
b = bytes.fromhex(_s.pop(False))
except IndexError:
b = b""
logging.info("opaque data is %s octets", len(b))
# Needs to be multiple of 4 in length
mod = len(b) % 4
if mod:
b += b"\x00" * (4 - mod)
logging.info("opaque padding to %s octets", len(b))
await c.add_opaque_data(*oargs, b) await c.add_opaque_data(*oargs, b)
else: else:
assert what.casefold().startswith("del") assert what.casefold().startswith("del")
await c.delete_opaque_data(*oargs) f = 0
if len(_s) >= 1:
try:
f = int(_s.pop(False))
except IndexError:
f = 0
await c.delete_opaque_data(*oargs, f)
if args.exit: if args.exit:
return 0 return 0
except Exception as error: except Exception as error:
@ -1153,7 +1162,9 @@ def main(*args):
ap.add_argument("--server", default="localhost", help="OSPF API server") ap.add_argument("--server", default="localhost", help="OSPF API server")
ap.add_argument("-v", "--verbose", action="store_true", help="be verbose") ap.add_argument("-v", "--verbose", action="store_true", help="be verbose")
ap.add_argument( ap.add_argument(
"actions", nargs="*", help="(ADD|DEL),LSATYPE,[ADDR,],OTYPE,OID,[HEXDATA]" "actions",
nargs="*",
help="(ADD|DEL),LSATYPE,[ADDR,],OTYPE,OID,[HEXDATA|DEL_FLAG]",
) )
args = ap.parse_args() args = ap.parse_args()

View file

@ -534,7 +534,7 @@ struct msg *new_msg_originate_request(uint32_t seqnum, struct in_addr ifaddr,
struct msg *new_msg_delete_request(uint32_t seqnum, struct in_addr addr, struct msg *new_msg_delete_request(uint32_t seqnum, struct in_addr addr,
uint8_t lsa_type, uint8_t opaque_type, uint8_t lsa_type, uint8_t opaque_type,
uint32_t opaque_id) uint32_t opaque_id, uint8_t flags)
{ {
struct msg_delete_request dmsg; struct msg_delete_request dmsg;
dmsg.addr = addr; dmsg.addr = addr;
@ -542,6 +542,7 @@ struct msg *new_msg_delete_request(uint32_t seqnum, struct in_addr addr,
dmsg.opaque_type = opaque_type; dmsg.opaque_type = opaque_type;
dmsg.opaque_id = htonl(opaque_id); dmsg.opaque_id = htonl(opaque_id);
memset(&dmsg.pad, 0, sizeof(dmsg.pad)); memset(&dmsg.pad, 0, sizeof(dmsg.pad));
dmsg.flags = flags;
return msg_new(MSG_DELETE_REQUEST, &dmsg, seqnum, return msg_new(MSG_DELETE_REQUEST, &dmsg, seqnum,
sizeof(struct msg_delete_request)); sizeof(struct msg_delete_request));

View file

@ -185,11 +185,19 @@ struct msg_originate_request {
struct lsa_header data; struct lsa_header data;
}; };
/* OSPF API MSG Delete Flag. */
#define OSPF_API_DEL_ZERO_LEN_LSA 0x01 /* send withdrawal with no LSA data */
#define IS_DEL_ZERO_LEN_LSA(x) ((x)->flags & OSPF_API_DEL_ZERO_LEN_LSA)
struct msg_delete_request { struct msg_delete_request {
struct in_addr addr; /* intf IP for link local, area for type 10, "0.0.0.0" for AS-external */ struct in_addr addr; /* intf IP for link local, area for type 10,
"0.0.0.0" for AS-external */
uint8_t lsa_type; uint8_t lsa_type;
uint8_t opaque_type; uint8_t opaque_type;
uint8_t pad[2]; /* padding */ uint8_t pad; /* padding */
uint8_t flags; /* delete flags */
uint32_t opaque_id; uint32_t opaque_id;
}; };
@ -313,7 +321,7 @@ extern struct msg *new_msg_originate_request(uint32_t seqnum,
struct lsa_header *data); struct lsa_header *data);
extern struct msg *new_msg_delete_request(uint32_t seqnum, struct in_addr addr, extern struct msg *new_msg_delete_request(uint32_t seqnum, struct in_addr addr,
uint8_t lsa_type, uint8_t opaque_type, uint8_t lsa_type, uint8_t opaque_type,
uint32_t opaque_id); uint32_t opaque_id, uint8_t flags);
/* Messages sent by OSPF daemon */ /* Messages sent by OSPF daemon */
extern struct msg *new_msg_reply(uint32_t seqnum, uint8_t rc); extern struct msg *new_msg_reply(uint32_t seqnum, uint8_t rc);

View file

@ -1997,6 +1997,11 @@ int ospf_apiserver_handle_delete_request(struct ospf_apiserver *apiserv,
goto out; goto out;
} }
if (IS_DEL_ZERO_LEN_LSA(dmsg)) {
/* minimize the size of the withdrawal: */
old->opaque_zero_len_delete = 1;
}
/* Schedule flushing of LSA from LSDB */ /* Schedule flushing of LSA from LSDB */
/* NB: Multiple scheduling will produce a warning message, but harmless. /* NB: Multiple scheduling will produce a warning message, but harmless.
*/ */

View file

@ -190,6 +190,7 @@ struct ospf_lsa *ospf_lsa_new(void)
new->refresh_list = -1; new->refresh_list = -1;
new->vrf_id = VRF_DEFAULT; new->vrf_id = VRF_DEFAULT;
new->to_be_acknowledged = 0; new->to_be_acknowledged = 0;
new->opaque_zero_len_delete = 0;
return new; return new;
} }

View file

@ -124,6 +124,9 @@ struct ospf_lsa {
/*For topo chg detection in HELPER role*/ /*For topo chg detection in HELPER role*/
bool to_be_acknowledged; bool to_be_acknowledged;
/* send maxage with no data */
bool opaque_zero_len_delete;
}; };
/* OSPF LSA Link Type. */ /* OSPF LSA Link Type. */

View file

@ -2050,6 +2050,17 @@ void ospf_opaque_lsa_flush_schedule(struct ospf_lsa *lsa0)
goto out; goto out;
} }
if (lsa->opaque_zero_len_delete &&
lsa->data->length != htons(sizeof(struct lsa_header))) {
/* minimize the size of the withdrawal: */
/* increment the sequence number and make len just header */
/* and update checksum */
lsa->data->ls_seqnum = lsa_seqnum_increment(lsa);
lsa->data->length = htons(sizeof(struct lsa_header));
lsa->data->checksum = 0;
lsa->data->checksum = ospf_lsa_checksum(lsa->data);
}
/* Delete this lsa from neighbor retransmit-list. */ /* Delete this lsa from neighbor retransmit-list. */
switch (lsa->data->type) { switch (lsa->data->type) {
case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_LINK_LSA: